提问者:小点点

如何访问存储在std::variant中类的方法


我正在尝试访问std::variant中保存的类的方法。 不幸的是,它抛出了以下错误:

class ’std::variant<A, int>’ has no member named ‘function’

代码:

class A {
private:
    int number = 0;
public:
    A() {};
    void function(int i) {
        number += i;
    }
};

// ... main ...
std::variant<A,B> array[4][4];

array[0][0] = A(){};
array[0][0].function(3);

我尝试阅读文档,但是我仍然不明白如何或者是否应该使用std::get()和std::variants.index()来访问上述方法。

读了一些文章之后,我尝试在循环中做了这样的事情:

std::size_t t=array[i][j].index();
std::get<t>(array[i][j]).function();

但还是没起作用。 错误是:

note: candidate: template<class _Tp, class ... _Types> constexpr _Tp&& std::get(std::variant<_Types ...>&&)
     constexpr inline _Tp&& get(variant<_Types...>&& __v)

template argument deduction/substitution failed:

共3个答案

匿名用户

要初始化std::variant中的值,可以使用std::get,或者从C++17开始,使用emplace():

array[0][0].emplace<A>();

要访问值,请使用std::get:

std::get<A>(array[0][0]).function(3);

此外,在编译时必须知道std::get的模板参数,因此当t是变量时,std::get将不起作用。 你可以稍微改变一下,例如:

std::size_t t = array[0][0].index();
switch (t) {
case 0:
    std::get<0>(array[0][0]).function(3);
case 1:
    // . . .
}

匿名用户

STD::GET是您正在寻找的解决方案。

std::get<A>(array[0][0]) = AA();
std::get<A>(array[0][0]).function(3);

std::get<int>(array[0][0]) = 56;

还有一件事,您可以使用std::array代替这个C数组,并获得更多标准库功能:

std::array<std::array<std::variant<A,int>, 4>, 4> array;

用法仍然可以是相同的,或者更安全一点:

std::get<A>(std::get<0>(std::get<0>(array))) = A();

或者:

std::get<A>(array.at(0).at(0)) = A();

在这种情况下,对于数组使用operator[]可能不会在索引错误的情况下引发错误。 您最好使用.at()函数,该函数将在超出访问范围的情况下引发异常:

try {
    std::get<A>(array.at(0).at(0)) = A();
} catch (const std::out_of_range& e) {
    std::cout << e.what() << std::endl;
}

阅读有关std::out_of_range的信息。

std::size_t t = array[i][j].index();
std::get<t>(array[i][j]).function(); // Error!

不能将非常量值用作模板参数。 模板参数是在编译期间分析的,这里t只有在运行时才知道。 请参考以下问题:尝试使用std::visit和lambda表达式从std::variant返回值

阅读有关变体的更多信息

匿名用户

调用get方法,将变量作为参数并指定模板的类

例:假设您有一个具有x,y坐标的点类,那么std::get(v)将允许您访问变量中的点

std::variant<int, Point> v;
v = 177;
int i = std::get<int>(v);
v = Point(15,18);

try 
{
  Point s = std::get<Point>(v);
  std::cout << s.getX();
}
catch (const std::bad_variant_access&) {}