类模板专用化部分排序和函数合成
Class template specialization partial ordering and function synthesis
选择首选类模板专用化的规则包括将专用化重写为函数模板,并通过函数模板的排序规则 [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
之间。但是为什么?合成的函数模板没有歧义。这两种情况有什么区别?
Clang 与 GCC 兼容(并且与依赖于这两种行为的现有代码兼容)。
考虑[temp.deduct.type]p1:
[...]尝试查找模板参数值(类型参数的类型,非类型参数的值或模板参数的模板),在替换推导的值(称为推导的A)后,将使P与A兼容。
问题的症结在于"兼容"在这里的含义。
当对函数模板进行部分排序时,Clang只是在两个方向上推导;如果推导在一个方向上成功,而在另一个方向上没有成功,它假设这意味着结果将是"兼容的",并将其用作排序结果。
但是,当对类模板部分专用化进行部分排序时,Clang 将"兼容"解释为"相同"的含义。因此,它只认为一个部分专业化比另一个更专业,如果将其中一个的推导论点代入另一个可以重现原始的部分专业化。
更改这两者中的任何一个以匹配另一个会破坏大量实际代码。 :(
相关文章:
- 是否有类似std::lower_bound的函数,而不需要排序/分区输入
- std::sort()函数无法对向量的一部分进行排序
- 使用自定义比较函数使用std::sort()对矢量字符串进行排序时出现问题
- 用于合并排序的合并函数
- 如何计算此排序函数的时间复杂度?
- 什么是自定义比较器以及如何在 C++ 的排序函数中使用它?
- 为什么用户定义的函数不按照给定的顺序对相同长度的元素进行排序?
- 自定义排序函数中的堆溢出
- 分段 排序函数实现中的错误
- 使用模板化分配器和对向量进行排序的函数
- 为什么我的函数接受"std::string"进行排序不会改变它?
- 对没有比较器或λ函数的向量进行排序?
- C++中的析构函数和构造函数排序
- 数组中的函数排序错误
- 如何命名比较谓词函数排序向量
- 按lexicographical_compare()函数排序
- 构造函数排序(全局作用域)问题
- 按接受c++中参数的函数排序
- 函数排序错误
- 根据不同函数排序的std::向量的交集