为什么在声明要使用 `enable_if` 进行专门化的 class 模板时需要 `void`

Why `void` is required while declaring a class template which is to be specialized using `enable_if`

我正在学习 C++ 模板元编程,偶然发现了一个简单的 SFINAE 相关(我相信如此)问题。特别是,我正在编写一个模板 class,它将为我们提供最大尺寸的类型。通过将类型与 sizeof 运算符进行比较,我将 type 别名为正确的类型,具体取决于它们的大小。我正在使用 enable_if 选择正确的 class 专业化。我不明白的是为什么在声明要使用 enable_if.[=23 专门化的 class 模板时需要将 void 作为 class Enable 的默认值提供=]

以下代码工作正常

// test.cpp
#include <type_traits>

// void works just fine but if changed to anything else say int, compilation fails!
template < typename L, typename R, class Enable = void > struct MaxTypeT;

template < typename L, typename R >
struct MaxTypeT<L, R, typename std::enable_if< (sizeof(L) >= sizeof(R)) >::type> {
    using type = L;
};

template < typename L, typename R >
struct MaxTypeT<L, R, typename std::enable_if< (sizeof(L) < sizeof(R)) >::type> {
    using type = R;
};

int main(){
    static_assert(std::is_same< MaxTypeT<int, double>::type, double >::value, "MaxTypeT not working");
    return 0;
}

但是当我将 class Enable = void 更改为任何其他类型时说 class Enable = int,然后我得到以下错误。为什么这里需要void

test.cpp: In function ‘int main()’:
test.cpp:17:56: error: incomplete type ‘MaxTypeT<int, double>’ used in nested name specifier
     static_assert(std::is_same< MaxTypeT<int, double>::type, double >::value, "MaxTypeT not working");
                                                        ^~~~
test.cpp:17:56: error: incomplete type ‘MaxTypeT<int, double>’ used in nested name specifier
test.cpp:17:69: error: template argument 1 is invalid
     static_assert(std::is_same< MaxTypeT<int, double>::type, double >::value, "MaxTypeT not working");

void 不是必需的,它只是为您节省了一些输入时间。如果你想在那里有 int 那么你也许应该这样写:

// test.cpp
#include <type_traits>

// int works just fine now
template < typename L, typename R, typename Enable = int > struct MaxTypeT;


// note additional template argument of enable_if
template < typename L, typename R >
struct MaxTypeT<L, R, typename std::enable_if< (sizeof(L) >= sizeof(R)), int >::type> {
    using type = L;
};

template < typename L, typename R >
struct MaxTypeT<L, R, typename std::enable_if< (sizeof(L) < sizeof(R)), int >::type> {
    using type = R;
};

int main(){
    static_assert(std::is_same< MaxTypeT<int, double>::type, double >::value, "MaxTypeT not working");
    return 0;
}

enable if 的第二个参数默认为 void,因此要匹配它,您的模板也必须有 void 或为 enable_if 提供不同的类型.

std::enable_if<>::type 默认为 void。因此,在模板替换发生后,您的每个特化都有第三个参数 void

// primary template
template < typename L, typename R, typename Enable = void > struct MaxTypeT;

// specialization #1
template < typename L, typename R >
struct MaxTypeT<L, R, void> {
    using type = L;
};

// specialization #2
template < typename L, typename R >
struct MaxTypeT<L, R, void> {
    using type = R;
};

当您执行 MaxTypeT<int, double> 时,它会实例化类型 MaxTypeT<int, double, void>,因为默认参数 Enable 设置为 void

如果 Enable 设置为 int,它实例化类型 MaxTypeT<int, double, int>。由于编译器无法将特化与这些参数类型相匹配,因此它与仅声明但未定义的主模板一起使用,因此出现错误。

正如 在他的回答中所说 std::enable_if 有第二个模板参数,指定其 ::type 成员将是什么。如果你将它设置为 int 那么它将是一个特化,在成功的模板替换之后第三个参数为 int