C++的std::visit如何使用
导读:本文共4016.5字符,通常情况下阅读需要13分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: 1. 使用对象函数方式访问例1:#include<iostream>#include<variant>#include<string>structMyVisitor{voidoperator()(doubled)const{std::cout<<d<<'\n';}voi... ...
目录
(为您整理了一些要点),点击可以直达。1. 使用对象函数方式访问
例1:
#include<iostream>#include<variant>#include<string>structMyVisitor{voidoperator()(doubled)const{std::cout<<d<<'\n';}voidoperator()(inti)const{std::cout<<i<<'\n';}voidoperator()(conststd::string&s)const{std::cout<<s<<'\n';}};intmain(){std::variant<int,double,std::string>var1(42),var2(3.14),var3("visit");std::visit(MyVisitor(),var1);//callsoperator()formatchinginttypestd::visit(MyVisitor(),var2);//callsoperator()formatchingdoubletypestd::visit(MyVisitor(),var3);//callsoperator()formatchingstd::stringtypereturn0;}
结果如下:
如果操作符()不支持所有可能的类型,或者调用不明确,则visit()调用是编译时错误。还可以使用访问者修改当前类型的值(但不能分配新类型的值)。
例2:
#include<iostream>#include<variant>#include<string>structTwice{voidoperator()(double&d)const{d*=2;}voidoperator()(int&i)const{i*=2;}voidoperator()(std::string&s)const{s=s+s;}};intmain(){std::variant<int,double,std::string>var1(42),var2(3.14),var3("visit");std::visit(Twice(),var1);//callsoperator()formatchinginttypestd::visit(Twice(),var2);//callsoperator()formatchingdoubletypestd::visit(Twice(),var3);//callsoperator()formatchingstd::stringtypestd::cout<<std::get<int>(var1)<<std::endl;std::cout<<std::get<double>(var2)<<std::endl;std::cout<<std::get<std::string>(var3)<<std::endl;return0;}
结果如下:
注意,对象操作符应该为const函数,因为它们是无状态的(它们不改变它们的行为,只改变传递的值,即不改变成员变量的值)。
2. 使用泛型Lambdas访问
使用这个特性最简单的方法是使用泛型lambda,它是一个函数对象,用于任意类型:
例3:
#include<iostream>#include<variant>#include<string>autoprintvariant=[](constauto&val){std::cout<<val<<std::endl;};intmain(){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);return0;}
结果如下:
这里,泛型lambda定义了一个闭包类型,其中函数调用操作符作为成员模板:
classCompilerSpecifyClosureTypeName{public:template<typenameT>autooperator()(constT&val)const{std::cout<<val<<'\n';}};
也可以使用lambda来修改当前选项的值:
例4:
#include<iostream>#include<variant>#include<string>autoprintvariant=[](constauto&val){std::cout<<val<<std::endl;};intmain(){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);return0;}
结果如下:
甚至可以使用编译时if语言特性以不同的方式处理不同的备选值:
例5:
#include<iostream>#include<variant>#include<string>autodblvar=[](auto&val){ifconstexpr(std::is_convertible_v<decltype(val),std::string>){val=val+"test";}else{val+=2;}};intmain(){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;return0;}
这里,对于一个std::string类型备选项,泛型lambda的调用实例化它的泛型函数调用模板来计算:
val = val + “ test”;
而对于其他类型备选项,如int或double, lambda的调用实例化其通用函数调用模板来计算:
val += 2;
结果如下:
3. 使用重载的Lambdas来访问
通过为函数对象和lambdas使用一个重载器,还可以定义一组lambdas,其中使用最佳匹配作为访问者。假设,重载器定义为重载,如下所示:
template<typename...Ts>structoverload:Ts...{usingTs::operator()...;};//basetypesarededucedfrompassedarguments:template<typename...Ts>overload(Ts...)->overload<Ts...>;
可以使用重载访问一个变量,为每个选项提供lambdas:
std::variant<int,std::string>var(42);...std::visit(overload{//callsbestmatchinglambdaforcurrentalternative[](inti){std::cout<<"int:"<<i<<'\n';},[](conststd::string&s){std::cout<<"string:"<<s<<'\n';},},var);
还可以使用泛型lambda。总是用最好的搭配。例如,要修改variant对象的当前类型备选项的值,可以使用重载将字符串和其他类型的值“加倍”:
autotwice=overload{[](std::string&s){s+=s;},[](auto&i){i*=2;},};
使用此重载,对于字符串类型备选项,将添加当前值,而对于所有其他类型,将值乘以2,这演示了variant对象的以下应用程序:
std::variant<int,std::string>var(42);std::visit(twice,var);//value42becomes84...var="hi";std::visit(twice,var);//value"hi"becomes"hihi"
例 6:
#include<iostream>#include<variant>#include<string>template<typename...Ts>structoverload:Ts...{usingTs::operator()...;};template<typename...Ts>overload(Ts...)->overload<Ts...>;autotwice=overload{[](std::string&s){s+=s;},[](auto&i){i*=2;},};intmain(){std::variant<int,std::string>var1(42),var3("visit");std::visit(twice,var1);std::visit(twice,var3);std::visit(overload{//callsbestmatchinglambdaforcurrentalternative[](inti){std::cout<<"int:"<<i<<'\n';},[](conststd::string&s){std::cout<<"string:"<<s<<'\n';},},var1);std::visit(overload{//callsbestmatchinglambdaforcurrentalternative[](inti){std::cout<<"int:"<<i<<'\n';},[](conststd::string&s){std::cout<<"string:"<<s<<'\n';},},var3);return0;}
结果如下:
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
C++的std::visit如何使用的详细内容,希望对您有所帮助,信息来源于网络。