SFINAE的专业课

Specializing class with SFINAE

本文关键字:专业课 SFINAE      更新时间:2023-10-16

我想写一个template class,它用SFINAE检查特征。

正如我在那篇文章中所读到的那样,类不能"重载":模板重载和SFINAE只能处理函数,而不能处理类

我写了以下代码:

class AA { public: using TRAIT = int; };
class BB { public: using TRAIT = float; };
template < typename T, typename UNUSED = void> class X;
template < typename T>
class X<T, typename std::enable_if< std::is_same< int, typename T::TRAIT>::value, int >::type>
{
    public:
        X() { std::cout << "First" << std::endl; }
 };
template < typename T>
class X<T, typename std::enable_if< !std::is_same< int, typename T::TRAIT>::value, unsigned int >::type>
{
    public:
        X() { std::cout << "Second" << std::endl; }
};
int main()
{
    X<AA> a;
    X<BB> b;
}

但它只是失败了:

error: aggregate 'X<AA> a' has incomplete type and cannot be defined
         X<AA> a;
               ^
error: aggregate 'X<BB> b' has incomplete type and cannot be defined
         X<BB> b;

它发现没有一个模板可以工作,但我没有从编译器那里得到为什么两个专业化都失败的提示。

专业化必须与主专业相匹配。确定什么是X<AA>的查找规则是首先匹配主类型并添加默认类型,这将使我们进入X<AA, void>,然后尝试将其与所有专业化相匹配。但你的专业没有一个能与X<AA, void>相匹配,所以你最终获得了初选。主类型不是一个完整的类型,因此出现错误。

为什么它们都不匹配?因为你写了:

typename std::enable_if< std::is_same< int, typename T::TRAIT>::value, int >::type

对于评估为intAA,它与void不匹配,因此不考虑专门化。你只想:

typename std::enable_if< std::is_same< int, typename T::TRAIT>::value>::type

或者真的:

std::enable_if_t< std::is_same< int, typename T::TRAIT>::value>

类似地,对于BB,第二个专门化的第二个类型计算为unsigned int,而不是void,因此它也不匹配。