首页 > 解决方案 > 奇怪的g ++编译器行为在模板函数中键入id

问题描述

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

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?

更新:可重现的错误

标签: c++templates

解决方案


您的错误的原因是ifs 基本上是运行时构造,而模板是编译时构造。

这真正意味着,在编译之后,您的模板函数将如下所示:

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;
    }
}

标准 if需要能够运行它的主体,以防条件永远为真。所以,它被编译了,它失败了。


关于这个还能做什么?有多种选择。

最接近您的解决方案是使用新的 C++17 if constexpr。此构造的行为与常规 完全相同if,只是在编译时对其进行评估。缺点是表达式必须可以在编译时求值(它必须是一个constexpr表达式),并且operator==for 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)

第三种方法是做一些模板专业化(我个人认为在这种特定情况下这不是一个好主意)。


推荐阅读