前言
std::visit
是 C++17 中引入的一个模板函数,它用于对给定的 variant
、union
类型或任何其他兼容的类型执行一个访问者操作。这个函数为多种可能类型的值提供了一种统一的访问机制。使用 std::visit
,你可以编写更通用和灵活的代码,而无需关心具体是哪种类型的值。
实践
市面上大部分例子都是只访问一个variant, 我们写个不同的,实际visit支持一下放入多个variant, 参考语法:
#include <iostream>
#include <variant>
#include <string>
using namespace std;// Define alternative types
using Variant1 = std::variant<int, double>;
using Variant2 = std::variant<int,char>;struct MyVisitor {//对每一种组合都必须定义一个处理函数。少一个编译都会失败。void operator()(int value1, int value2) const {std::cout << value1<<value2<<endl;}void operator()(int value1, char value2) const {std::cout << value1<<value2<<endl;}void operator()(double value1, int value2) const {std::cout << value1<<value2<<endl;}void operator()(double value1, char value2) const {std::cout <<value1<<value2<<endl;}
};int main() {Variant1 var1;Variant2 var2;var1 = 42;var2 = 100;std::visit(MyVisitor{}, var1, var2); var1 = 3.14;var2 = 'a';std::visit(MyVisitor{}, var1, var2);return 0;
}
啰嗦一句,因为我们四个函数体相似,正是用模板的好时机,把它们改成一句话:
void operator()(auto&& value1, auto&& value2) const {std::cout << value1<<value2<<endl; }
如果不放心,丢到cppinsights里看看展开:
四个函数不论手写还是自动生成缺一不可,它们其实是两个variant的alternative types的组合,即int/double 与 int/char的所有组合。缺一不可和gcc的实现有关,下面会说到。
visit的原理
这次我们不看晦涩的代码,而是通过GDB快速理解visit的原理。
调试到21行 std::visit(MyVisitor{}, var1, var2);
s进入,慢慢到下面这个位置:
打印__vtable: 它生成了一个2*2的二维数组,里面放了函数指针,对应所有组合。
不要被名字所误解,vtable不是virtual table的意思。
此时var1 var2里面装的都是int,都是各自类型列表中的第一个类型 (var1.index(), var2.index()), __func_ptr应该取得了__vtable[0][0]的值即0x40160f
确实如此。
咱们这是从现象推原理,如果还想了解vtable怎么生成的,可能这篇文章对你有帮助:
Variant Visitation – Michael Park
Variant Visitation V2 – Michael Park