#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::type”,那么这个推导是否成功呢?后者是一种替换失败,所以我不知道这个推导怎么可能成功。
在这种情况下,gcc和clang为什么更喜欢使用“a”重载呢?
typename identity<UniqueB>::type --> UniqueB_2
的问题。你想将所有这些内容合并成一个答案吗? - Barrytypename identity<T>::type
参数的考虑。 - Barry