https://cloud.tencent.com/developer/article/1351910
[譯]C++17,optional, any, 和 variant 的更多細節版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/tkokof1/article/details/82660834
std::optional, std::any, 和 std::variant 有一個共同特點:他們都支持就地構造.另外的,std::variant 還支持訪問者模式. 首先,我們要了解一下這3種數據類型的功能作用.
我在之前的文章中講解了這3個數據類型的一些細節,不了解的朋友可以先去看看,相關內容這里就不再贅述了. ![]() Construct in-place什么是就地構造呢?以 std::optional<std::string> 為例來說明就是: 所謂就地構造,就是你可以直接使用 std::string 的構造參數來構造 std::optional<std::string>. 下面是一個簡短的示例. #include <optional> #include <iostream> #include <string> int main() { std::cout << std::endl; std::optional<std::string> opt1(std::in_place, "C++17"); std::optional<std::string> opt2(std::in_place, 5, 'C'); std::optional<std::string> opt3(std::in_place, { 'C', '+', '+', '1', '7' }); std::optional<std::string> opt4(opt3); std::cout << *opt1 << std::endl; std::cout << *opt2 << std::endl; std::cout << *opt3 << std::endl; std::cout << *opt4 << std::endl; std::cout << std::endl; return 0; } 代碼中的 opt1(第10行), op2(第13行) 和 op3(第16行) 都使用了 std::in_place 標記來進行構造,這意味着 std::optional 的構造參數將直接用於調用 std::string 的構造函數.所以在上述代碼中, opt1 中 std::string 的構造函數參數即為 C 風格字符串(“C++17”), op2 中是5個單字符’C’, op3 中則是初始化列表({ ‘C’, ‘+’, ‘+’, ‘1’, ‘7’ }).另外,代碼中的 opt4(第19行)並未使用就地構造方法,而是調用了 std::optional 的復制構造函數(復制了op3). 程序的輸出如下: ![]() 上述的就地構造是不是覺得有些熟悉?其實早在 C++11 中,標准庫容器就引入很多用於增加容器元素的接口方法,這些方法都以 emplace 開頭,功能上就是提供了就地構造的方法.以 std::vector<int> vec 為例,借助其支持的 emplace_back 方法,我們可以直接調用 vec.emplace_back(5) 來增加 vec 的末尾元素,這等同於下面代碼: vec.push_back(int(5)). std::variant 還支持 std::visit 方法(即精典的設計模式:訪問者). Visit a list of variantsstd::visit 方法允許你對一個 std::variants 列表應用訪問者模式,而相應的訪問者必須是一個callable類型,所謂 callable 類型,是一種可以被調用的類型,通常是一個函數,一個函數對象或者一個 lambda 函數.簡單起見,這里我僅使用 lambda 函數來舉例說明. #include <iostream> #include <vector> #include <typeinfo> #include <type_traits> #include <variant> int main() { std::cout << std::endl; std::vector<std::variant<char, long, float, int, double, long long>> vecVariant = { 5, '2', 5.4, 100ll, 2011l, 3.5f, 2017 }; for (auto& v : vecVariant) { std::visit([](auto&& arg) {std::cout << arg << " "; }, v); } std::cout << std::endl; for (auto& v : vecVariant) { std::visit([](auto&& arg) {std::cout << typeid(arg).name() << " "; }, v); } std::cout << std::endl; std::common_type<char, long, float, int, double, long long>::type res{}; std::cout << "typeid(res).name(): " << typeid(res).name() << std::endl; for (auto& v : vecVariant) { std::visit([&res](auto&& arg) {res += arg; }, v); } std::cout << "res: " << res << std::endl; for (auto& v : vecVariant) { std::visit([](auto&& arg) {arg *= 2; }, v); std::visit([](auto&& arg) {std::cout << arg << " "; }, v); } std::cout << std::endl; return 0; } 代碼中我創建了 std::variants 的列表(代碼第11行).每個 variant 都可以包含以下的任一類型:char, long, float, int, double, long long.遍歷 variant 列表並對每一個 variant 應用 lambda 函數非常簡單(代碼第15行到17行).借助 typeid 函數,我便可以獲得 variant 的實際類型(代碼第22行到24行).到這里,我想你應該已經看出了代碼中的訪問者模式, std::vector<std::variant> 就是我應用各種函數(即訪問者)的被訪問數據結構. 現在,我想將各個 variant 的元素求和.求和之前,我需要在編譯期確定所求和的結果類型,為此我使用了 std::common_type (代碼第29行), std::common_type 可以給出 char, long, float, int, double, 和 long long 都可以進行隱式轉換的類型(double類型).代碼中的 res{} 定義將 res(求和結果) 初始化為了 0.0,並在第33行到35行執行了真正的求和操作.我甚至使用訪問者動態的修改了 variant 中的元素(代碼第40行). 程序的輸出如下.Visual C++ 中的運行時類型信息(std::type_info)給出了非常易讀的類型名稱. ![]() |
|
C++17 基本完成,對於新特性大家怎么看? - 知乎 https://www.zhihu.com/question/56943731
C++17 的特性探索
https://alexiachen.github.io/blog/2017/08/31/explore-cpp17/
- 前言
- Optional
- Variant
- Any
- std::string_view
- std::invoke
- std::apply
- 類模版參數推導
- 用auto聲明無類型的模版參數
- Folding表達式
- 在花括號初始化列表中的auto推導的新規則
- constexpr的lambda表達式
- lambda以值方式捕獲this指針
- 內聯變量
- 嵌套namespace
- Structured bindings
- constexpr if
- UTF-8字符字面量
隨筆分類 - C++
ReactiveX 學習筆記(29)使用 RxCpp(RxQt)+ Qt 進行 GUI 編程
posted @ 2019-06-17 14:13 zwvista 閱讀 (68) | 評論 (0) 編輯
ReactiveX 學習筆記(24)使用 RxCpp + C++ REST SDK 調用 REST API
posted @ 2018-09-07 21:57 zwvista 閱讀 (705) | 評論 (0) 編輯
編程漫談系列(4)協變(covariance),逆變(contravariance)與不變(invariance)
posted @ 2017-11-02 20:31 zwvista 閱讀 (133) | 評論 (0) 編輯
C++17嘗鮮:結構化綁定聲明(Structured Binding Declaration)
posted @ 2017-05-29 00:43 zwvista 閱讀 (281) | 評論 (0) 編輯