选择哪个类模板特化是首选的规则包括将特化重写为函数模板,并通过函数模板的排序规则 [temp.class.order] 确定哪个函数模板更特化。考虑这个例子,然后:
#include <iostream>
template <class T> struct voider { using type = void; };
template <class T> using void_t = typename voider<T>::type;
template <class T, class U> struct A { };
template <class T> int foo(A<T, void_t<T>> ) { return 1; }
template <class T> int foo(A<T*, void> ) { return 2; }
int main() {
std::cout << foo(A<int*, void>{});
}
gcc 和 clang 都2
在这里打印。这对于前面的一些示例是有意义的 - 对非推导上下文 (void
反对void_t<T>
) 的推导只是被忽略了,因此在两个论点中对推导<T, void_t<T>>
成功<X*, void>
但<T*, void>
对推导<Y, void_t<Y>>
失败。美好的。
现在考虑这个概括:
#include <iostream>
template <class T> struct voider { using type = void; };
template <class T> using void_t = typename voider<T>::type;
template <int I> struct int_ { static constexpr int value = I; };
template <class T, class U> struct A : int_<0> { };
template <class T> struct A<T, void_t<T>> : int_<1> { };
template <class T> struct A<T*, void> : int_<2> { };
int main() {
std::cout << A<int*, void>::value << '\n';
}
clang 和 gcc 都将这种专业化报告为模棱两可,介于1
和之间2
。但为什么?合成的函数模板没有歧义。这两种情况有什么区别?