c – 为什么SFINAE需要’Enable’类模板参数?

(这个问题与C 11 / C 14无关:这些例子是用C 03编写的)

enable_bool< T>只有当T是bool时才有成员:: type

template <class T>
struct enable_bool
{};

template <>
struct enable_bool< bool >
{ typedef bool type; };

在下一个片段中,部分特化是正确的(参见gcc.godbolt.org)

template <class T, class U, class Enable = T>
struct Foo
{
    static int bar() { return 0; }
};

template <class T, class U>
struct Foo< T, U, typename enable_bool<T>::type >
{
    static int bar() { return 1; }
};

int main()
{
    return Foo <int, bool>::bar();
}

因为enable_bool< T> :: type已经对应于T(当T是bool时)
我们很想将参数T和Enable分解.
但编译器抱怨(见gcc.godbolt.org)

template <class T, class U>
struct Foo
{
    static int bar() { return 0; }
};

template <class T, class U> //ERROR non-deducible template parameter 'T'
struct Foo< typename enable_bool<T>::type, U >
{
    static int bar() { return 1; }
};

为什么编译器不能在上面的部分特化中推导出模板参数?

最佳答案 最后这个问题甚至与SFINAE无关!

考虑一下没有SFINAE的这个非常简单的片段:
无论提供的T类型如何,enable< T> :: type始终与T相同.

template <class T>
struct enable
{ typedef T type; };       // Enable always

template <class U, class V>
struct Foo
{
    static int bar() { return 0; }
};

template <class X, class Y> //ERROR non-deducible parameter 'X'
struct Foo< typename enable<X>::type, Y >
{
    static int bar() { return 1; }
};

int main()
{
    return Foo<int, bool>::bar();
}

当编译器尝试匹配Foo< int,bool>使用Foo< typename enable< X> :: type,Y>

>第一个参数U = int< – >启用< X> :: type =>不能推断X.
>第二个参数V = bool< – > ÿ

编译器不是为了从等式int = enable< X> :: type中推导出X.
因此,编译器需要开发人员的帮助.
需要另一个参数:启用.

以下固定的代码段添加了Enable class template参数.
编译器执行以下匹配:

>第一个参数U = int< – > X
>第二个参数V = bool< – > ÿ
> 3rd param Enable = int< – > enable< X> :: type(从第一个参数中推导出X)
(第3个参数是int,因为声明类Enable = U表示默认第3个参数与第1个参数相同)

修正片段:

template <class T>
struct enable
{ typedef T type; };       // Enable always

template <class U, class V, class Enable = U>
struct Foo
{
    static int bar() { return 0; }
};

template <class X, class Y> // Compiler can deduce 'X'
struct Foo< X, Y, typename enable<X>::type >
{
    static int bar() { return 1; }
};

int main()
{
    return Foo<int, bool>::bar();
}
点赞