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

时间:2017-05-18 22:32:09

标签: c++ c++17 variant visitor-pattern

早些时候我向question询问std::variant。考虑到变体所持有的类型都可以由std::cout打印,是否有一种简单的方法来实现访问者?

例如,

Here,你一直都有几个lambdas来覆盖每个类型,但所有都做同样的事情(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);

1 个答案:

答案 0 :(得分:2)

无需复制

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__ )

#define OVERLOADS_OF(...) \
  [](auto&&...args) \
  RETURNS( __VA_ARGS__(decltype(args)(args)...) ) \
  { return __VA_ARGS__(decltype(args)(args)...); }
然后我们得到:

template<typename T>
void printer(T arg) {std::cout << arg; }

std::visit(OVERLOADS_OF(printer), v);

创建一个匿名对象,该对象表示由令牌printer命名的函数的重载集。