std::enable_if 使用其内部类型和不使用它

std::enable_if using its internal type and without using it

为什么会打印"B"

#include <iostream>

template<typename T, typename U = void>
struct Test
{ static void apply() { std::cout << "A" << std::endl; } };

template<typename T>
struct Test<T, typename std::enable_if<true>::type>
{ static void apply() { std::cout << "B" << std::endl; } };

int main()
{
    Test<int>::apply();
}

但是这个 "A"?:

#include <iostream>

template<typename T, typename U = void>
struct Test
{ static void apply() { std::cout << "A" << std::endl; } };

template<typename T>
struct Test<T, std::enable_if<true>>
{ static void apply() { std::cout << "B" << std::endl; } };

int main()
{
    Test<int>::apply();
}

它们之间的唯一区别是,在第一个中,我将 typename std::enable_it<true>::type 用作 U(例如,void),但在第二个中,我我直接将 std::enable_if<true> 用作 U,这也是一个定义明确的类型,没有更多的含义,如 void

由于 typename std::enable_if<true>::typevoid 的类型相同,因此第一个片段相当于

template<typename T, typename U = void>
struct Test
{ static void apply() { std::cout << "A" << std::endl; } };

template<typename T>
struct Test<T, void> // since typename std::enable_if<true>::type == void
{ static void apply() { std::cout << "B" << std::endl; } };

因此,第二个定义更专业,因此如果您不提供两个模板参数,则后者在重载决策中获胜。

然而,在第二个例子中,你只是对 Tstd::enable_if<true> 这对类型的特化,而不是 Tvoid 的特化。 这可以用 std::is_same<std::enable_if<true>, void> 来检查,它的计算结果为 false(显然,void 没有类型成员 type,所以它不可能相同)。

因此,对于第二个片段,请求 T<int> 将与 T<int, void> 匹配,其中只有一个定义相关,即第一个。

因为当你写 Test<int> 时,你实际上写的是 Test<int, void>,它永远不会与 Test<int, std::enable_if<true>> 相同(尽管它与 Test<int, typename std::enable_if<true>::type> 相同)