C++17嘗鮮


 


 

 

 

https://cloud.tencent.com/developer/article/1351910

 

[譯]C++17,optional, any, 和 variant 的更多細節

版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/tkokof1/article/details/82660834

看到一個介紹 C++17 的系列博文(原文),有十來篇的樣子,覺得挺好,看看有時間能不能都簡單翻譯一下,這是第六篇~

std::optional, std::any, 和 std::variant 有一個共同特點:他們都支持就地構造.另外的,std::variant 還支持訪問者模式.

首先,我們要了解一下這3種數據類型的功能作用.

  • std::optional 是一種可能包含也可能不包含某一類型對象的類型.
  • std::variant 是一種類型安全的聯合體
  • std::any 是一種可以包含任意類型(指可復制類型)對象的類型

我在之前的文章中講解了這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 variants

std::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/

 

  1. 前言
  2. Optional
  3. Variant
  4. Any
  5. std::string_view
  6. std::invoke
  7. std::apply
  8. 類模版參數推導
  9. 用auto聲明無類型的模版參數
  10. Folding表達式
  11. 在花括號初始化列表中的auto推導的新規則
  12. constexpr的lambda表達式
  13. lambda以值方式捕獲this指針
  14. 內聯變量
  15. 嵌套namespace
  16. Structured bindings
  17. constexpr if
  18. UTF-8字符字面量

 

 

 


 

 

 

 

 

 


 

 

 

 

 

 


 

 


 

隨筆分類 - C++

ReactiveX 學習筆記(29)使用 RxCpp(RxQt)+ Qt 進行 GUI 編程
 

posted @ 2019-06-17 14:13 zwvista 閱讀 (68) |  評論 (0) 編輯

趣味編程:靜夜思(C++17 Ranges版)
 

posted @ 2019-06-07 18:28 zwvista 閱讀 (39) |  評論 (0) 編輯

ReactiveX 學習筆記(24)使用 RxCpp + C++ REST SDK 調用 REST API
 

posted @ 2018-09-07 21:57 zwvista 閱讀 (705) |  評論 (0) 編輯

JSON數據的解析和生成(C++)
 

posted @ 2018-09-05 14:21 zwvista 閱讀 (2012) |  評論 (0) 編輯

ReactiveX 學習筆記(23)RxCpp
 

posted @ 2018-09-04 23:43 zwvista 閱讀 (953) |  評論 (0) 編輯

使用 C++ REST SDK 進行網絡編程
 

posted @ 2018-09-03 22:03 zwvista 閱讀 (1825) |  評論 (0) 編輯

C++17嘗鮮:變長 using 聲明
 

posted @ 2018-07-03 01:43 zwvista 閱讀 (174) |  評論 (0) 編輯

C++17嘗鮮:編譯期 if 語句
 

posted @ 2018-06-28 13:44 zwvista 閱讀 (325) |  評論 (0) 編輯

C++17嘗鮮:variant
 

posted @ 2018-06-28 09:46 zwvista 閱讀 (441) |  評論 (0) 編輯

C++17嘗鮮:string_view
 

posted @ 2018-06-27 12:57 zwvista 閱讀 (1623) |  評論 (0) 編輯

正則表達式(Java,C#,C++)
 

posted @ 2017-11-26 16:14 zwvista 閱讀 (146) |  評論 (0) 編輯

Boost.Hana
 

posted @ 2017-11-23 20:12 zwvista 閱讀 (228) |  評論 (0) 編輯

編程漫談系列(4)協變(covariance),逆變(contravariance)與不變(invariance)
 

posted @ 2017-11-02 20:31 zwvista 閱讀 (133) |  評論 (0) 編輯

Boost.Coroutine2:學習使用Coroutine(協程)
 

posted @ 2017-10-31 22:47 zwvista 閱讀 (1000) |  評論 (0) 編輯

C++17嘗鮮:類模板中的模板參數自動推導
 

posted @ 2017-10-28 22:21 zwvista 閱讀 (1181) |  評論 (0) 編輯

趣味編程:CPS風格代碼(C++11, C++14版)
 

posted @ 2017-10-20 00:05 zwvista 閱讀 (84) |  評論 (0) 編輯

C++17嘗鮮:在 if 和 switch 語句中進行初始化
 

posted @ 2017-10-16 09:03 zwvista 閱讀 (967) |  評論 (0) 編輯

C++17嘗鮮:結構化綁定聲明(Structured Binding Declaration)
 

posted @ 2017-05-29 00:43 zwvista 閱讀 (281) |  評論 (0) 編輯

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM