为什么 SFINAE 需要"启用"类模板参数?

Why SFINAE requires the 'Enable' class template parameter?

本文关键字:参数 启用 SFINAE 需要 为什么      更新时间:2023-10-16

(此问题与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(当Tbool时)
我们很想分解参数TEnable
但是编译器抱怨(见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; }
};

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

最后这个问题甚至与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>匹配时

  • 1st param U = int <--> enable<X>::type =>无法推断X
  • 2nd param V = bool <--> Y

编译器不能从方程int = enable<X>::type推导出X
因此,编译器需要开发人员的帮助。
需要另一个参数:Enable .

下面的固定代码段添加了Enable类模板参数。编译器执行以下匹配:

  • 1st param U =int <--> X
  • 2nd param V =bool<--> Y
  • 3rd param Enable=int <--> enable<X>::type(从第1参数推导出X)
    (第三个参数是int,因为声明class Enable=U默认表示第三个参数与第一个相同)

固定的片段:

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