在不知道哪个值处于活动状态的情况下获取 std::visit 中的活动值

Getting active value in std::visit without knowing which value is active

我想在 std::variant 中获取活动值,但不知道哪个是活动的。我以为我可以写一个模板访问者并使用 std::visit 但它不起作用。

#include <variant>
#include <string>
#include <iostream>

struct Visit_configuration {
    template<typename Data_type>
    Data_type operator()(Data_type& t) const
    {
        return t;
    }
};

int main()
{
    std::variant<int, std::string> v;
    v = "hello";

    std::cout << std::visit(Visit_configuration(), v);   // expect "hello"
    std::cin.get();
}

MSVC 不编译并抛出:

error C2338: visit() requires the result of all potential invocations to have the same type and value category (N4741 23.7.7 [variant.visit]/2).

note: see reference to function template instantiation 'int std::visit&,0>(_Callable &&,std::variant &)' being compiled

那么如何解决这个问题?

编辑:我想将获得的值也用于其他值,因此将 cout 放入模板并不是我想要的。

Return 访问者函数类型应该相同。

改为创建打印机访问者:

struct PrinterVisitor {
    template<typename T>
    void operator()(const T& t) const
    {
        std::cout << t;
    }
};

int main()
{
    std::variant<int, std::string> v;
    v = "hello";

    std::visit(PrinterVisitor{}, v);   // expect "hello"
}

在您的情况下,您甚至可以使用 lambda:

int main()
{
    std::variant<int, std::string> v;
    v = "hello";

    std::visit([](const auto& t){std::cout << t;}, v);   // expect "hello"
}

问自己这个问题:
如果您不知道 variant 的哪一部分是活动的,那么 std::visit 的 return 类型是什么?

这是编译器必须回答的问题。答案不能是 "it depends" - 你(就像编译器一样)必须在编译时决定 恰好是一种类型 visit 调用在 运行 时不可能 return 不同类型。

如果您想使用不同的类型 "at runtime",您必须在以您要使用的类型为模板的函数中。换句话说,必须是不同的函数(或函数模板实例化)来处理"write an int to cout"和"write a string to cout"情况。您不能在同一个(非模板化)函数中执行此操作。

因此,这里直接的解决方案是将 std::cout << 放入您的模板化访问者函数中 - 这就是访问的重点:指定在每种情况下应该发生什么。

如果您想 "use the obtained value maybe also for [some] other [purpose]",那么 "other purpose" 也应该是 the/a 访问者的一部分。只有这样你才能让 "other purpose" 一次处理不同的情况(例如在模板函数中)。否则,您必须在编译时就已经决定要使用哪种类型——编译器不会将该选择保留到以后(运行 时间)。