c++ - 奇怪的 g++ 编译器在模板函数中对 typeid 的行为

标签 c++ templates

我尝试创建一些多态类成员模板函数来处理多种类型:

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?

更新:reproducable error

最佳答案

错误的原因是 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/

相关文章:

c++ - 模板中的 typename U = equal_to<T> 是什么意思? STL equal_to<T> 用法

c++ - 在 C++ 中获取广泛的类型错误

c++ - 哪个是正确的 : vector<const string> OR const vector<string>?

c++ - 在 C++ 中使用 JNI 时出现 c0000005 异常(访问冲突)

c++ - 令我惊讶的是,这段代码可以正确编译和执行。这里发生了什么事?

python - 将 HTML 输出导出为 pdf 或 odt 的合适模板系统是什么?

iphone - 如何将 XCode 项目保存为模板以供其他应用使用?

c++ - std::void_t 和嵌套非类型成员

c++ - 大csv文件c++解析性能

java - 循环无向图中的所有可能路径