早些时候我问过这个关于std::variant
的
问题。考虑到变体持有的类型都可以通过
std::cout
打印,有没有简单的方法来实现访问者?
这里例如,一路下来你有几个lambda来覆盖每种类型,但都做同样的事情(除了
std::string
):std::cout << arg << ' ';
。有没有办法不重复自己?
std::visit(overloaded {
[](int arg) { std::cout << arg; },
[](long arg) { std::cout << arg; },
[](double arg) { std::cout << arg; }
// I removed the std::string case
}, v); // v is the std::variant
然后写:
std::visit( [](auto arg) { std::cout << arg; }, v);
或者类似的东西:
template<typename T>
void printer(T arg) {std::cout << arg; }
//.......
std::visit(printer, v);
无需复制
std::visit( [](auto&& arg) { std::cout << arg; }, v);
这需要
arg
(转发)参考。我懒得转发;我不在乎它是右值还是左值。
模板函数不起作用,因为访问需要一个对象,而模板函数不是函数的对象;您(还)无法将重载集名称作为 C++ 中的对象传递。
overload
技巧主要是当你想要调度不同的行为时。
你能做的一件事是
template<typename T>
void printer(T arg) {std::cout << arg; }
std::visit([](auto&&arg){printer(arg);}, v);
或
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype( __VA_ARGS__ ) \
{ return __VA_ARGS__; }
#define OVERLOADS_OF(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__(decltype(args)(args)...) )
然后我们得到:
template<typename T>
void printer(T arg) {std::cout << arg; }
std::visit(OVERLOADS_OF(printer), v);
它创建一个匿名对象,该对象表示由标记
printer
命名的函数重载集。
我遇到的问题是,除了几个不同的
std::variant
之外,还有一个 std::monostate
。我没有超载,而是这样解决的:std::vector<T>
不是最优雅的,但很简单,可能会让你到达你想要的地方。