具有默认参数的模板特化

Template specialisation with default argument

我有一个程序如下。有一个基本模板 struct X 和 SFINAE 的部分专业化。

template <typename T, typename U = void>
struct X{
  X() {
    std::cout << "in 1" << std::endl;
  };
};

template <typename T>
struct X< T, std::enable_if_t<std::is_integral_v<T>> > {
  X() {
    std::cout << "in 2" << std::endl;
  };
};

int main() {
  X<int> x;
}

当运行时,程序in 2被打印出来。

  1. 为什么选择第二个专业而不是第一个,因为他们都有效地声明了 struct X<int, void>。是什么让 std::enable_if_t<std::is_integral_v<T>> 比基本模板中显示的默认模板类型参数更专业?

  2. 为什么基本模板的默认类型参数必须与偏特化定义的类型相同才能调用偏特化并打印in 2。 为什么更改为 std::enable_if_t<std::is_integral_v<T>, bool> 会导致调用基本模板 in 1

您问题的答案在Template Partial Ordering中。这是编译器用来确定哪个模板最合适的机制(无论是函数模板重载,还是在您的情况下,class 模板特化)。

简而言之,您的通用模板实现有 2 个参数 TU,而您的 SFINAE 专业化只有 T 参数,而第二个是从 T.因此,它比一般情况更专业化,最后,当您参考 X<int, void> 时,选择了专业化。

现在问题2。假设我们将enable_if参数替换为bool而不是void。现在我们的专业化将是 X<int, bool> 而不是 X<int, void>,所以当您引用 X<int>,即 X<int, void>,它不再匹配专业化,因为它们是 2 种不同的类型.

1) [...] What makes std::enable_if_t> more specialised than a default template type argument as shown in the base template?

那么你知道吗,如果两个模板匹配,则选择更专业的。

嗯......第二个更专业,因为如果 X 匹配专业化(所以如果 X 是一个整数类型),它也匹配通用版本。

但是存在一些匹配通用版本但不匹配专业版本的类型(例如:std::stringvoid)。

所以专业版比通用版更专业,所以当两个模板匹配时首选。

Why does the default type argument of the base template have to be the same as the type defined by the partial specialisation for the partial specialisation to be called and in 2 to be printed. Why does changing to std::enable_if_t, bool> cause the base template in 1 to be called?

您必须了解默认类型值的技巧。

你有通用版本

template <typename T, typename U = void>
struct X;

所以写 X<int> x,你写的是 X<int, void> x; 并且肯定与通用版本匹配。

专业是

template <typename T>
struct X< T, std::enable_if_t<std::is_integral_v<T>>>;

问题:X<int, void> 匹配 X< T, std::enable_if_t<std::is_integral_v<T>>> ?

答:可以,因为int是整数,所以std::enable_if_t<std::is_integral_v<T>>void代替。

现在假设通用专业化变成

template <typename T>
struct X< T, std::enable_if_t<std::is_integral_v<T>, bool>>

我们知道 X<int> x 又是 X<int, void> x 并再次匹配通用版本。

问题:X<int, void> 也匹配 X< T, std::enable_if_t<std::is_integral_v<T>, bool>> ?

回答:不会,因为std::enable_if_t<std::is_integral_v<T>, bool>变成了boolX<int, void>不匹配X<int, bool>

因此通用版本是唯一匹配并被选中的版本。