C++17之std::visit的具體使用
它們必須明確地為每種可能的類型提供函數(shù)調(diào)用操作符。然后,使用相應的重載來處理當前的備選項類型。
1. 使用對象函數(shù)方式訪問
例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;
}結果如下:

如果操作符()不支持所有可能的類型,或者調(diào)用不明確,則visit()調(diào)用是編譯時錯誤。還可以使用訪問者修改當前類型的值(但不能分配新類型的值)。
例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函數(shù),因為它們是無狀態(tài)的(它們不改變它們的行為,只改變傳遞的值,即不改變成員變量的值)。
2. 使用泛型Lambdas訪問
使用這個特性最簡單的方法是使用泛型lambda,它是一個函數(shù)對象,用于任意類型:
例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定義了一個閉包類型,其中函數(shù)調(diào)用操作符作為成員模板:
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的調(diào)用實例化它的泛型函數(shù)調(diào)用模板來計算:
val = val + “ test”;
而對于其他類型備選項,如int或double, lambda的調(diào)用實例化其通用函數(shù)調(diào)用模板來計算:
val += 2;
結果如下:

3. 使用重載的Lambdas來訪問
通過為函數(shù)對象和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;
}結果如下:

到此這篇關于C++17之std::visit的具體使用的文章就介紹到這了,更多相關C++17 std::visit內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++利用代理模式實現(xiàn)遠程代理,虛擬代理和保護代理
今天給大家簡單介紹代理模式,一個很簡單的設計模式,旨在不改變原對象的情況下通過代理對象來控制對原對象的訪問。代理模式根據(jù)具體情況還可以分為遠程代理、虛擬代理、保護代理等,下面來介紹一下2023-04-04

