考虑以下简单(就模板问题而言)示例:
#include <iostream>
template <typename T>
struct identity;
template <>
struct identity<int> {
using type = int;
};
template<typename T> void bar(T, T ) { std::cout << "a\n"; }
template<typename T> void bar(T, typename identity<T>::type) { std::cout << "b\n"; }
int main ()
{
bar(0, 0);
}
clang 和 gcc 都在那里打印“a”。根据[temp.deduct.partial]和[temp.func.order]中的规则,要确定偏序,我们需要合成一些唯一的类型。所以我们有两次推演尝试:
+---+-------------------------------+-------------------------------------------+
| | Parameters | Arguments |
+---+-------------------------------+-------------------------------------------+
| a | T, typename identity<T>::type | UniqueA, UniqueA |
| b | T, T | UniqueB, typename identity<UniqueB>::type |
+---+-------------------------------+-------------------------------------------+
对于“b”的推论,根据Richard Corden 的回答,表达式typename identity<UniqueB>::type
被视为一种类型并且不被评估。也就是说,这将被合成为:
+---+-------------------------------+--------------------+
| | Parameters | Arguments |
+---+-------------------------------+--------------------+
| a | T, typename identity<T>::type | UniqueA, UniqueA |
| b | T, T | UniqueB, UniqueB_2 |
+---+-------------------------------+--------------------+
很明显,对“b”的推论失败了。这是两种不同的类型,因此您不能同时推断出这两种类型T
。
但是,在我看来,扣除A
应该失败。对于第一个参数,您将匹配T == UniqueA
. 第二个论点是一个非演绎的上下文 - 那么如果UniqueA
可以转换为,那么演绎不会成功identity<UniqueA>::type
吗?后者是替换失败,所以我看不出这个推论怎么会成功。
在这种情况下,gcc 和 clang 如何以及为什么更喜欢“a”重载?