Хорошо, так что есть о чем поговорить.
Во-первых, посетитель для std::visit
с более чем одним аргументом варианта должен принять все комбинации вариантов типов. В вашем случае он должен принять:
(string, string)
(string, int)
(int, int)
(int, string)
Если для вас действительны только string, string
и int, 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
s, которые у вас есть.
Итак, окончательный код такой:
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; }