C++17之std::visit的具體使用
它們必須明確地為每種可能的類型提供函數(shù)調(diào)用操作符。然后,使用相應(yīng)的重載來(lái)處理當(dāng)前的備選項(xiàng)類型。
1. 使用對(duì)象函數(shù)方式訪問(wèn)
例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; }
結(jié)果如下:
如果操作符()不支持所有可能的類型,或者調(diào)用不明確,則visit()調(diào)用是編譯時(shí)錯(cuò)誤。還可以使用訪問(wèn)者修改當(dāng)前類型的值(但不能分配新類型的值)。
例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; }
結(jié)果如下:
注意,對(duì)象操作符應(yīng)該為const函數(shù),因?yàn)樗鼈兪菬o(wú)狀態(tài)的(它們不改變它們的行為,只改變傳遞的值,即不改變成員變量的值)。
2. 使用泛型Lambdas訪問(wèn)
使用這個(gè)特性最簡(jiǎn)單的方法是使用泛型lambda,它是一個(gè)函數(shù)對(duì)象,用于任意類型:
例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; }
結(jié)果如下:
這里,泛型lambda定義了一個(gè)閉包類型,其中函數(shù)調(diào)用操作符作為成員模板:
class CompilerSpecifyClosureTypeName { public: template<typename T> auto operator() (const T& val) const { std::cout << val << '\n'; } };
也可以使用lambda來(lái)修改當(dāng)前選項(xiàng)的值:
例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; }
結(jié)果如下:
甚至可以使用編譯時(shí)if語(yǔ)言特性以不同的方式處理不同的備選值:
例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; }
這里,對(duì)于一個(gè)std::string類型備選項(xiàng),泛型lambda的調(diào)用實(shí)例化它的泛型函數(shù)調(diào)用模板來(lái)計(jì)算:
val = val + “ test”;
而對(duì)于其他類型備選項(xiàng),如int或double, lambda的調(diào)用實(shí)例化其通用函數(shù)調(diào)用模板來(lái)計(jì)算:
val += 2;
結(jié)果如下:
3. 使用重載的Lambdas來(lái)訪問(wèn)
通過(guò)為函數(shù)對(duì)象和lambdas使用一個(gè)重載器,還可以定義一組lambdas,其中使用最佳匹配作為訪問(wèn)者。假設(shè),重載器定義為重載,如下所示:
template<typename... Ts> struct overload : Ts... { using Ts::operator()...; }; // base types are deduced from passed arguments: template<typename... Ts> overload(Ts...) -> overload<Ts...>;
可以使用重載訪問(wèn)一個(gè)變量,為每個(gè)選項(xiàng)提供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對(duì)象的當(dāng)前類型備選項(xiàng)的值,可以使用重載將字符串和其他類型的值“加倍”:
auto twice = overload{ [](std::string& s) { s += s; }, [](auto& i) { i *= 2; }, };
使用此重載,對(duì)于字符串類型備選項(xiàng),將添加當(dāng)前值,而對(duì)于所有其他類型,將值乘以2,這演示了variant對(duì)象的以下應(yīng)用程序:
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; }
結(jié)果如下:
到此這篇關(guān)于C++17之std::visit的具體使用的文章就介紹到這了,更多相關(guān)C++17 std::visit內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)生成新春福字的示例詳解
這篇文章主要介紹了如何利用C語(yǔ)言實(shí)現(xiàn)生成各個(gè)字體的新春福字,再也不用擔(dān)心支付寶掃福找不到圖片了,感興趣的同學(xué)可以跟隨小編學(xué)習(xí)一下2022-01-01C++中vector類的一些簡(jiǎn)單實(shí)現(xiàn)
C++中的std::vector是一個(gè)動(dòng)態(tài)數(shù)組(也被稱為可變大小數(shù)組)的容器類,它是C++標(biāo)準(zhǔn)庫(kù)提供的其中一種容器類,提供了方便的操作和管理動(dòng)態(tài)數(shù)組的功能,本文就給大家介紹了C++中vector類的簡(jiǎn)單實(shí)現(xiàn)代碼,需要的朋友可以參考下2023-08-08C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易三子棋
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易三子棋,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07C語(yǔ)言實(shí)現(xiàn)停車管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)停車管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03C++利用代理模式實(shí)現(xiàn)遠(yuǎn)程代理,虛擬代理和保護(hù)代理
今天給大家簡(jiǎn)單介紹代理模式,一個(gè)很簡(jiǎn)單的設(shè)計(jì)模式,旨在不改變?cè)瓕?duì)象的情況下通過(guò)代理對(duì)象來(lái)控制對(duì)原對(duì)象的訪問(wèn)。代理模式根據(jù)具體情況還可以分為遠(yuǎn)程代理、虛擬代理、保護(hù)代理等,下面來(lái)介紹一下2023-04-04C++實(shí)現(xiàn)的大數(shù)相乘算法示例
這篇文章主要介紹了C++實(shí)現(xiàn)的大數(shù)相乘算法,結(jié)合實(shí)例形式分析了C++大數(shù)相乘的概念、原理及代碼實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-08-08