为什么编译器不拾取基于enable_if的专门化

Why specialization based on enable_if is not picked up by compiler

本文关键字:enable if 专门化 编译器 为什么      更新时间:2023-10-16

我想为某些类型的类专门化class,例如基于std::is_arithmetic。虽然编译器不会"看到"我的基于"enable_if"的专门化,并选择原则/主模板。你能帮我解决这个问题吗?下面是用g++ 4.8编译后的代码片段和输出

#include < iostream >  
#include < type_traits >  
#include < string >  
template < typename T1, typename T2 = void >  
struct TestT  
{  
    static const bool is_int = false;  
    static const bool is_str = false;  
};
template < typename T>  
struct TestT < T,  
       std::enable_if< std::is_arithmetic<t>::value, T >::type >  
{  
    static const bool is_int = true;  
    static const bool is_str = false;  
};  
template < typename T>
struct TestT < std::string, T >  
{  
    static const bool is_int = false;  
    static const bool is_str = true;  
};  
class enum TestE  
{  
    Last  
};
int main(int argc, char* argv[])  
{
    std::cout << "Enum is_int: " << TestT<TestE>::is_int  
              << ", is_str: " << TestT<TestE>::is_str << std::endl;  
    std::cout << "string is_int: " << TestT<std::string>::is_int  
              << ", is_str: " << TestT<std::string>::is_str << std::endl;  
    std::cout << "int is_int: " << TestT<int>::is_int  
              << ", is_str: " << TestT<int>::is_str << std::endl;  
    return 0;
}  

以上输出为:

Enum is_int: 0, is_str: 0//预期
string is_int: 0, is_str: 1//期望
int is_int: 0, is_str: 0//不期望

我真的很感激任何帮助,并提前感谢您

您需要将第二个参数(以::type别名的类型)保留为未指定或void,以便它与主模板的默认参数相匹配:

struct TestT<T,  
       std::enable_if<std::is_arithmetic<T>::value>::type> 

您还需要在std::enable_if语句之前使用typename,或者使用std::enable_if_t(省略::type):

struct TestT<T, std::enable_if_t<std::is_arithmetic<T>::value>>

第二个专门化也是如此:

template<>
struct TestT<std::string>  
{  
    static const bool is_int = false;  
    static const bool is_str = true;  
};
最后,在这个专门化中,is_int应该设置为true:
template<typename T>  
struct TestT<T, std::enable_if_t<std::is_arithmetic<T>::value>>  
{  
    static const bool is_int = true;  
    static const bool is_str = false;  
};

现场演示

一个更好的版本可能是保持单一的专门化,使用std::is_same来测试int,使用类型trait来测试字符串:

template<class T>struct is_string:std::false_type{};
template<>struct is_string<std::string>:std::true_type{};
template<std::size_t N>struct is_string<char const(&)[N]>:std::true_type{};
template<>struct is_string<char const*>:std::true_type{};
template<>struct is_string<char const*const>:std::true_type{};
template<>struct is_string<char const*volatile>:std::true_type{};
// on and on...
template<typename T>  
struct TestT  
{  
    static const bool is_int = std::is_same<T, int>();  
    static const bool is_str = is_string<T>();  
};