我尝试创建一些多态类成员模板函数来处理多种类型:
class MyClass
{
public:
template<typename T>
void AddType(T value);
private:
bool b_val;
int i_val;
std::string str_val;
}
template<typename T>
void MyClass::AddType(T value)
{
if(typeid(T) == typeid(bool))
{
b_val = value;
}
else if(typeid(T) == typeid(int))
{
i_val = value;
}
else if(typeid(T) == typeid(std::string))
{
str_val = val
}
}
用法:
MyClass message;
std::string s = "string";
int i = 123;
message.AddType(s);
message.AddType(i);
由于某种原因我得到编译器错误:
error: assigning to 'bool' from incompatible type 'std::__cxx11::basic_string<char>'
b_val = value;
^~~~~
note: in instantiation of function template specialization 'MyClass::AddType<std::__cxx11::basic_string<char> >' requested here
message.AddType(s);
为什么编译器猜测 T 是 std::string?
最佳答案
错误的原因是 if
基本上是运行时构造,而模板是编译时构造。
这真正的意思是,在编译之后,您的模板函数看起来像这样:
void MyClass::AddType(std::string value)
{
if(some_value_for_typeid(std::string) == some_value_for_typeid(bool))
{
b_val = value;
}
else if(some_value_for_typeid(std::string) == some_value_for_typeid(int))
{
i_val = value;
}
}
让我们更清楚一点:
void MyClass::AddType(std::string value)
{
if(2 == 3)
{
b_val = value;
}
else if(2 == 5)
{
i_val = value;
}
}
标准如果需要能够运行它的主体,以防条件永远为真。所以,它被编译了,但失败了。
对此可以做些什么?有多种选择。
最接近您的解决方案是使用新的 C++17 if constexpr
.此构造的行为与常规 if
完全相同,只是在编译时对其进行评估。缺点是表达式必须可以在编译时求值(它必须是 constexpr
表达式),operator==
用于 std::type_info
(typeid
返回的东西)不是 constexpr。但是,有 std::is_same
,它以 constexpr 方式进行类型比较:
template<typename T>
void MyClass::AddType(T value)
{
if constexpr (std::is_same<T, bool>::value) {
b_val = value;
} else if constexpr (std::is_same<T, bool>::value) {
i_val = value;
}
}
编译时,整个 if 结构将简化为 b_val = value;
、i_val = value;
或什么都没有。
另一种选择是通过简单地定义 MyClass::AddType(bool);
和 MyClass::AddType(int)
来简单地重载函数。
第三种方法是做一些 template specialization (我个人认为在这种特定情况下这不是一个好主意)。
关于c++ - 奇怪的 g++ 编译器在模板函数中对 typeid 的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58318288/