網站首頁 編程語言 正文
? ? 它們必須明確地為每種可能的類型提供函數調用操作符。然后,使用相應的重載來處理當前的備選項類型。
1. 使用對象函數方式訪問
例1:
#include <iostream> #include <variant> #include <string> struct MyVisitor { void operator()(double d) const { std::cout << d << '\n'; } void operator()(int i) const { std::cout << i << '\n'; } void operator()(const std::string& s) const { std::cout << s << '\n'; } }; int main() { std::variant<int, double, std::string> var1(42), var2(3.14), var3("visit"); std::visit(MyVisitor(), var1); // calls operator() for matching int type std::visit(MyVisitor(), var2); // calls operator() for matching double type std::visit(MyVisitor(), var3); // calls operator() for matching std::string type return 0; }
結果如下:
?如果操作符()不支持所有可能的類型,或者調用不明確,則visit()調用是編譯時錯誤。還可以使用訪問者修改當前類型的值(但不能分配新類型的值)。
例2:
#include <iostream> #include <variant> #include <string> struct Twice { void operator()(double& d) const { d *= 2; } void operator()(int& i) const { i *= 2; } void operator()(std::string& s) const { s = s + s; } }; int main() { std::variant<int, double, std::string> var1(42), var2(3.14), var3("visit"); std::visit(Twice(), var1); // calls operator() for matching int type std::visit(Twice(), var2); // calls operator() for matching double type std::visit(Twice(), var3); // calls operator() for matching std::string type std::cout << std::get<int>(var1) << std::endl; std::cout << std::get<double>(var2) << std::endl; std::cout << std::get<std::string>(var3) << std::endl; return 0; }
結果如下:
注意,對象操作符應該為const函數,因為它們是無狀態的(它們不改變它們的行為,只改變傳遞的值,即不改變成員變量的值)。?
?2. 使用泛型Lambdas訪問
使用這個特性最簡單的方法是使用泛型lambda,它是一個函數對象,用于任意類型:
例3:
#include <iostream> #include <variant> #include <string> auto printvariant = [](const auto& val) { std::cout << val << std::endl; }; int main() { std::variant<int, double, std::string> var1(42), var2(3.14), var3("visit"); std::visit(printvariant, var1); std::visit(printvariant, var2); std::visit(printvariant, var3); return 0; }
結果如下:
?這里,泛型lambda定義了一個閉包類型,其中函數調用操作符作為成員模板:
class CompilerSpecifyClosureTypeName { public: template<typename T> auto operator() (const T& val) const { std::cout << val << '\n'; } };
也可以使用lambda來修改當前選項的值:
例4:
#include <iostream> #include <variant> #include <string> auto printvariant = [](const auto& val) { std::cout << val << std::endl; }; int main() { std::variant<int, double, std::string> var1(42), var2(3.14), var3("visit"); std::visit([](auto& val) { val = val + val; }, var1); std::visit([](auto& val) { val = val + val; }, var2); std::visit([](auto& val) { val = val + val; }, var3); std::visit(printvariant, var1); std::visit(printvariant, var2); std::visit(printvariant, var3); return 0; }
結果如下:
甚至可以使用編譯時if語言特性以不同的方式處理不同的備選值:
例5:
#include <iostream> #include <variant> #include <string> auto dblvar = [](auto& val) { if constexpr (std::is_convertible_v<decltype(val), std::string>) { val = val + " test"; } else { val += 2; } }; int main() { std::variant<int, double, std::string> var1(42), var2(3.14), var3("visit"); std::visit(dblvar, var1); std::visit(dblvar, var2); std::visit(dblvar, var3); std::cout << std::get<int>(var1) << std::endl; std::cout << std::get<double>(var2) << std::endl; std::cout << std::get<std::string>(var3) << std::endl; return 0; }
這里,對于一個std::string類型備選項,泛型lambda的調用實例化它的泛型函數調用模板來計算:
val = val + “ test”;
而對于其他類型備選項,如int或double, lambda的調用實例化其通用函數調用模板來計算:
val += 2;
結果如下:
3. 使用重載的Lambdas來訪問
通過為函數對象和lambdas使用一個重載器,還可以定義一組lambdas,其中使用最佳匹配作為訪問者。假設,重載器定義為重載,如下所示:
template<typename... Ts> struct overload : Ts... { using Ts::operator()...; }; // base types are deduced from passed arguments: template<typename... Ts> overload(Ts...) -> overload<Ts...>;
可以使用重載訪問一個變量,為每個選項提供lambdas:
std::variant<int, std::string> var(42); ... std::visit(overload{ // calls best matching lambda for current alternative [](int i) { std::cout << "int: " << i << '\n'; }, [](const std::string& s) { std::cout << "string: " << s << '\n'; }, }, var);
還可以使用泛型lambda。總是用最好的搭配。例如,要修改variant對象的當前類型備選項的值,可以使用重載將字符串和其他類型的值“加倍”:
auto twice = overload{ [](std::string& s) { s += s; }, [](auto& i) { i *= 2; }, };
? ? 使用此重載,對于字符串類型備選項,將添加當前值,而對于所有其他類型,將值乘以2,這演示了variant對象的以下應用程序:
std::variant<int, std::string> var(42); std::visit(twice, var); // value 42 becomes 84 ... var = "hi"; std::visit(twice, var); // value "hi" becomes "hihi"
例 6:
#include <iostream> #include <variant> #include <string> template<typename... Ts> struct overload : Ts... { using Ts::operator()...; }; template<typename... Ts> overload(Ts...)->overload<Ts...>; auto twice = overload{ [](std::string& s) { s += s; }, [](auto& i) { i *= 2; }, }; int main() { std::variant<int, std::string> var1(42) , var3("visit"); std::visit(twice, var1); std::visit(twice, var3); std::visit(overload{ // calls best matching lambda for current alternative [](int i) { std::cout << "int: " << i << '\n'; }, [](const std::string& s) { std::cout << "string: " << s << '\n'; }, }, var1); std::visit(overload{ // calls best matching lambda for current alternative [](int i) { std::cout << "int: " << i << '\n'; }, [](const std::string& s) { std::cout << "string: " << s << '\n'; }, }, var3); return 0; }
結果如下:
原文鏈接:https://blog.csdn.net/janeqi1987/article/details/100568146
相關推薦
- 2022-05-27 C++?動態規劃算法使用分析_C 語言
- 2022-07-04 反向傳播BP學習算法Gradient?Descent的推導過程_相關技巧
- 2022-06-01 C++構造函數的類型,淺拷貝與深拷貝詳解_C 語言
- 2022-06-26 詳解Python數據類型、進制轉換、字符串格式化的問題_python
- 2022-12-03 C++時間函數整理詳解_C 語言
- 2022-08-16 python+pytest接口自動化參數關聯_python
- 2022-12-16 C++?Boost?Atomic詳細講解_C 語言
- 2023-01-19 python圖形界面教程Tkinter詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支