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

r6l8ljro  于 2023-07-01  发布在  其他
关注(0)|答案(2)|浏览(112)

之前我问过这个关于std::variant的问题。考虑到该变体所包含的类型都可以由std::cout打印,有没有一种简单的方法来实现访问者?
例如Here,一路下来你有几个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);
lyr7nygr

lyr7nygr1#

不用抄

std::visit(  [](auto&& arg) { std::cout << arg; }, v);

这采用arg通过(转发)引用。我懒得转发我不在乎它是右值还是左值。
模板函数不起作用,因为visit需要一个对象,而模板函数不是函数的对象;在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);

其创建表示由令牌X1 M2 N1 X命名的函数的重载集的匿名对象。

sqyvllje

sqyvllje2#

我遇到了一个std::variant有一个std::monostate除了一对夫妇不同的std::vector<T>的问题。而不是重载,我这样解决它:

auto empty() const -> bool
{
    return std::visit([](auto arg) {
        // constexpr() does not work in a ternary operator...
        if constexpr(std::is_same<decltype(arg), std::monostate>()) {
            return true;
        }
        else {
            return arg.empty();
        }},
        v);
}

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

相关问题