c – 如何检查可能使用SFINAE的类型中的字段存在?

我有一个名为Traits的结构,它是类型为T的模板,Traits有一个名为Size的字段.当T实际上有一个名为Size的字段时,代码编译并且一切正常.但是,当T是本机类型时,它显然没有Size字段,并且代码无法编译

template <class T>
struct Traits
{
    static const size_t Size = T::Size;
};

我试图用SFINAE写它但它仍然无法编译

template <class T>
struct Traits
{
    static typename std::enable_if<!std::is_fundamental<T>::value, const size_t>::type Size = T::Size;
    static typename std::enable_if< std::is_fundamental<T>::value, const size_t>::type Size = sizeof(T);
};

编译错误是

error : redeclaration of `typename std::enable_if<std::is_fundamental<T>::value, const unsigned int>::type Traits<T>::Size'

这没有任何意义,因为编译器认为我正在重新声明Size但实际上它是不可能的,因为T是基本类型或不是因此我希望Size只被声明一次.

知道什么是错的或如何规避这个问题? (使用gcc 4.8.3)

最佳答案 SFINAE仅适用于某些情况,而这不是其中之一. SFINAE只能在类模板特化和函数模板签名的上下文中使用.将测试移动到类模板特化中,它应该按预期工作:

template <class T, class = void>
struct Traits  //default is is fundamental
{
    static const size_t Size = sizeof(T);
};
template<class T>
struct Traits<T,std::enable_if_t<!std::is_fundamental<T>::value>>{ //if SFINAE does not remove this it is not fundamental and should have a T::Size
    static const size_t Size = T::Size;
}

使用void_t直接测试T是否具有嵌套大小可能更好:

template<typename T>
using void_t = void;

template <class T, class = void>
struct Traits  //default 
{
    static const size_t Size = sizeof(T);
};
template<class T>
struct Traits<T,void_t<decltype(T::Size)>>{ //if SFINAE does not remove this T::Size exists
    static const size_t Size = T::Size;
}
点赞