模板适用于 std::variant 的访问吗?

问题描述 投票:0回答:2

早些时候我问过这个关于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);
c++ c++17 variant visitor-pattern
2个回答
4
投票

无需复制

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
命名的函数重载集。


0
投票

我遇到的问题是,除了几个不同的

std::variant
之外,还有一个
std::monostate
。我没有超载,而是这样解决的:
std::vector<T>

不是最优雅的,但很简单,可能会让你到达你想要的地方。

© www.soinside.com 2019 - 2024. All rights reserved.