我正在尝试使用std :: variant作为类成员变量,然后使用运算符重载,以便此类的两个Variants
可以使用运算符plus
生成一个新变量。问题是std :: get不能像我想象的那样工作,所以我无法检索正确的(硬编码)字符串类型,因此使用了AddVisitor
结构。
我收到一个编译错误:no matching function for call to ‘get<0>(std::basic_string&)’
还有一种方法,operator+
函数检测没有if-else
语句的类型?
我已经在SO中检查了很多答案,包括那些回答有关类似Boost功能的问题的答案,但我无法让它发挥作用。
#include <iostream>
#include <variant>
#include <string>
#include "stdafx.h"
using Variant = std::variant<int, std::string>;
template<typename T>
struct AddVisitor
{
T operator()(T v1, T v2)
{
return v1 + v2;
}
};
class Var
{
Variant v;
public:
template<typename T>
Var(T value) : v(value) {}
Var operator+(Var& val)
{
// PROBLEM: This is a hard coded example that I want to use, so that concatenation of two strings happens.
return std::visit(AddVisitor<std::string>(), std::get<std::string>(v), std::get<std::string>(val.get()));
// Is there a way to get the correct type without if-else statements here?
}
Variant get()
{
return v;
}
};
int main()
{
Var x("Hello "), y("World");
// The expected output is this:
Var res = x + y;
return 0;
}
我希望能够使用plus运算符并连接两个字符串或两个整数并创建一个新的Var
变量。
好的,所以有几件事要谈。
首先,具有多个变量参数的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; }