如何在带有模板函数的 class 中使用类型安全的联合(变体)?
How can I use type-safe unions (variants) inside a class with template functions?
我想用模板函数将 std::variant
放在 class 和 return 的元素中。这是一个例子:
#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;
}
我尝试通过模板函数fun
returnclassClass
的元素。但是,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
的第二个 return 类型)转换为 double
?我可以防止这种情况并解决问题吗?我是否使用 std::variant
class 单字?
这里的问题是你在运行时查询存储的当前值,而模板实例化的函数签名在编译时执行[=22] =].考虑当您尝试使用成员函数检索 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?!
}
这行不通。您需要更改访问数据成员的方式,例如通过提供两个 getter-like 函数返回 std::optional<double>
和 std::optional<std::string>
或类似的东西,将重载集传递给 std::visit
。
所有运行时 if 分支都必须是可编译的,即使没有采用。如果我们用 V == double
调用 fun()
那么 returning 一个 std::string
是没有意义的并且会导致错误(即使永远不会采用该分支,编译器也不知道那是肯定的)。
相反,只需 return 它立即通过 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.
}
我想用模板函数将 std::variant
放在 class 和 return 的元素中。这是一个例子:
#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;
}
我尝试通过模板函数fun
returnclassClass
的元素。但是,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
的第二个 return 类型)转换为 double
?我可以防止这种情况并解决问题吗?我是否使用 std::variant
class 单字?
这里的问题是你在运行时查询存储的当前值,而模板实例化的函数签名在编译时执行[=22] =].考虑当您尝试使用成员函数检索 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?!
}
这行不通。您需要更改访问数据成员的方式,例如通过提供两个 getter-like 函数返回 std::optional<double>
和 std::optional<std::string>
或类似的东西,将重载集传递给 std::visit
。
所有运行时 if 分支都必须是可编译的,即使没有采用。如果我们用 V == double
调用 fun()
那么 returning 一个 std::string
是没有意义的并且会导致错误(即使永远不会采用该分支,编译器也不知道那是肯定的)。
相反,只需 return 它立即通过 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.
}