在std :: visit中获取活动值而不知道哪个值是活动的

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

我想在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不编译和抛出:

错误C2338:visit()要求所有潜在调用的结果具有相同的类型和值类别(N4741 23.7.7 [variant.visit] / 2)。

注意:请参阅正在编译的函数模板实例化'int std :: visit&,0>(_ Callable &&,std :: variant&)'的引用

那么如何解决这个问题呢?

编辑:我想使用获得的值也许也适用于其他因此将cout放在模板中并不是我想要的。

c++ c++17 variant
2个回答
7
投票

问自己这个问题: 如果你不知道std::visit的哪个部分是活跃的,那么variant的返回类型是什么?

这是编译器必须回答的问题。答案不能“取决于” - 你(在编译器中)必须在编译时决定一种类型。 visit调用不可能在运行时返回不同的类型。

如果要“在运行时”使用不同类型,则必须使用模板化的函数来处理您要使用的类型。换句话说,必须有不同的函数(或函数模板实例)来处理“写一个int到cout”和“写一个字符串到cout”的情况。你不能在相同的(非模板化)函数中执行此操作。

因此,这里直截了当的解决方案是将std::cout <<放入模板化的访问者函数中 - 这就是访问的目的:指定在每种情况下应该发生的事情。

如果你想“使用获得的值也可能用于[某些]其他[目的]”,那么“其他目的”也应该是/访问者的一部分。只有这样,你才能让“其他目的”同时处理不同的情况(例如在模板化的函数中)。否则,您必须在编译时确定应该使用哪种类型 - 编译器不会将该选项打开以供稍后(运行时)使用。


3
投票

访问者功能的返回类型应该相同。

改为创建打印机访客:

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"
}
© www.soinside.com 2019 - 2024. All rights reserved.