我有一个如下程序。有一个基本模板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
被打印。
为什么选择第二个专业而不是第一个专业,因为它们两个都有效地声明了struct X<int, void>
。是什么使std::enable_if_t<std::is_integral_v<T>>
比基本模板中显示的默认模板类型参数更专业?
为什么基本模板的默认类型参数必须与要调用的部分专业化和要打印的in 2
的部分专业化定义的类型相同。
为什么更改为std::enable_if_t<std::is_integral_v<T>, bool>
会导致调用基本模板in 1
?
答案 0 :(得分:5)
问题的答案位于 Template Partial Ordering 中。这是编译器用来确定最适合的模板的机制(是函数模板重载,还是您的情况下,类模板专门化)。
简而言之,您的通用模板实现具有2个参数T
和U
,而SFINAE专业化仅具有T
参数,而第二个则是从T
推导出来的。因此,它比一般情况下更加专业,最后,当您引用X<int, void>
时,选择了专业化。
现在是问题2。假设我们用enable_if
代替bool
来代替void
参数。现在我们的专长将是X<int, bool>
而不是X<int, void>
,所以当您引用X<int>
即X<int, void>
时,它不再与专长匹配,因为这是2种不同的类型
答案 1 :(得分:1)
1)[...]是什么让std :: enable_if_t>比基本模板中显示的默认模板类型参数更专业?
因此,您知道吗,如果两个模板匹配,则选择的越专业。
嗯...第二个是更专业的,因为如果X
匹配专业化(因此,如果X
是整数类型),那么它也匹配通用版本。
但是存在几种类型(例如:std::string
,void
)与通用版本匹配,但与专业版本不匹配。
因此,专业化版本比通用版本更专业,因此当两个模板匹配时,首选。
为什么基本模板的默认类型参数必须与要调用的部分专业化和要打印的2中的部分专业化定义的类型相同。为什么更改为std :: enable_if_t,bool>会导致调用1中的基本模板?
您必须了解默认类型值的技巧是如何工作的。
您拥有的通用版本是
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>
变成了bool
并且X<int, void>
与X<int, bool>
不匹配
因此通用版本是唯一匹配并被选中的版本。