使用std :: variant作为班级成员并申请访问者

时间:2019-04-06 10:19:40

标签: c++ std variant

我试图将std :: variant用作类成员变量,然后使用运算符重载,以便该类的两个Permission可以使用运算符role.getPermissions()来生成新变量。问题在于std :: get无法按照我的想法工作,因此我无法检索正确的(硬编码)字符串类型,因此无法使用Role结构。

我收到一个编译错误,指出:Variants

还有没有一种方法,plus函数可以在没有AddVisitor语句的情况下检测类型?

我已经在SO中检查了很多答案,包括那些回答有关类似Boost功能的问题,但我无法使其正常工作。

no matching function for call to ‘get<0>(std::basic_string&)’

我希望能够使用加号运算符并连接两个字符串或两个整数并创建一个新的operator+变量。

1 个答案:

答案 0 :(得分:3)

好,所以有几件事要谈。

首先,具有多个变体参数的std::visit的访问者应接受变体类型的所有组合。就您而言,它应该接受:

  • (string, string)
  • (string, int)
  • (int, int)
  • (int, string)

如果仅string, stringint, int对您有效,那么您仍然需要接受其他组合才能编译代码,但可以将它们组合在一起。

接下来,不应该对访客进行模板化。相反,对于以上所有组合,operator()应该模板化或重载。

这里是AddVisitor

struct AddVisitor
{
    auto operator()(const std::string& a, const std::string& b) const -> Variant
    {
        return a + b;
    }
    auto operator()(int a, int b) const -> Variant
    {
        return a + b;
    }

    // all other overloads invalid
    template <class T, class U>
    auto operator()(T, U) const -> Variant
    {
        throw std::invalid_argument{"invalid"};
    }
};

从文档中还不清楚重载可以返回什么,但是除非全部返回Variant,否则我无法使其进行编译。幸运的是,编译器错误为 TREMENDOUSLY HELPFULL 。 (我需要检查标准)。

接下来,当您致电std::visit时,您需要传递您拥有的variant

最后的代码是这样:

auto operator+(Var& val) -> Var
{
    return std::visit(AddVisitor{}, get(), val.get());
}

您确实可以随意使用它:

Var res = x + y;

您的代码的另一个问题是get复制了不必要的副本。并且std::variant的副本并不便宜。所以我建议:

auto get() const -> const Variant&  { return v; }
auto get() -> Variant&  { return v; }