我想在类中放置std::variant
并使用模板函数返回其元素。这是一个示例:
#include <string>
#include <variant>
class Class {
public:
std::variant<std::string, double> cont;
Class() {}
template <class V> Class(const V v) { cont = v; }
template <typename V> V fun() {
if (std::holds_alternative<double>(cont))
return std::get<double>(cont);
else if (std::holds_alternative<std::string>(cont))
return std::get<std::string>(cont);
}
};
int main() {
Class c;
c = 20;
double d = c.fun<double>();
return 0;
}
我尝试通过模板函数Class
返回类fun
的元素。但是,gcc-9.1
拒绝编译代码并告诉我
Class.cpp:12:46: error: cannot convert ‘std::__cxx11::basic_string<char>’ to ‘double’ in return
12 | return std::get<std::string>(cont);
为什么要尝试将string
(函数foo
的第二种返回类型)转换为double
?我可以防止这种情况并解决问题吗?我可以单用std::variant
类吗?
答案 0 :(得分:3)
这里的问题是,您在运行时查询 中存储的当前值,而模板实例化的函数签名是在编译时 进行的。在尝试使用成员函数检索double
时,请考虑成员函数的外观:
double fun() {
if (/* ... */)
return std::get<double>(cont); // Ok return type is double, too
else if (/* ... */)
return std::get<std::string>(cont); // Error, return type should be string?!
}
这行不通。您需要更改访问数据成员的方式,例如通过提供两个返回std::optional<double>
和std::optional<std::string>
或类似方法的类似getter的函数,将重载设置传递给std::visit
。
答案 1 :(得分:2)
所有运行时,即使分支未使用也必须是可编译的。如果我们用fun()
调用V == double
,则返回std::string
毫无意义,并导致错误(即使永远不会采用该分支,编译器也无法确定)。
相反,只需通过V
立即将其返回:
template <typename V> V fun() {
if (std::holds_alternative<V>(cont))
return std::get<V>(cont);
return {}; // return default constructed V. You could throw an exception here instead etc.
}