为什么,在下面,调用了 bar
的实例化?没有歧义,而非模板重载函数foo
是模棱两可的。 nullptr
也是一样的而不是 NULL
#include <iostream>
template<typename T>
void bar (T*)
{
std::cout << "bar(T*)" << std::endl;
}
template<typename T>
void bar (typename T::value_type *)
{
std::cout << "bar(T::value_type*)" << std::endl;
}
struct A
{
using value_type = int;
};
void foo (A::value_type*)
{
std::cout << "foo(A::value_type *)" << std::endl;
}
void foo (A*)
{
std::cout << "foo(A *)" << std::endl;
}
int main ()
{
bar<A> (NULL);
foo (NULL); // ambigous
}
编辑:要清楚。我期待 foo
过载是模棱两可的。我不明白为什么 bar
实例化 bar<A>
时生成的重载不是同样模棱两可。
确定哪个过载是最后一个决胜局的最佳可行候选者的规则包括,来自 [over.match.best]:
Given these definitions, a viable function F1 is defined to be a better function than another viable function
F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
— [...]
— F1 and F2 are function template specializations, and the function template for F1 is more specialized
than the template for F2 according to the partial ordering rules described in 14.5.6.2.
只有当我们有两个具有相同转换序列的函数并且其中一个是或都不是函数模板时,才会达到该要点。对于 foo
,我们的两个重载候选者都具有相同的转换序列,函数模板也不是,最后一个要点不适用 - 所以它是模棱两可的。
不过,对于 bar
,我们可以尝试看看是否有一个
template<typename T> void bar (T*) // (1)
template<typename T> void bar (typename T::value_type *) // (2)
比另一个更专业。其规则基本上是尝试查看是否可以使用另一个参数调用一个函数。在这种情况下,任何 typename T::value_type*
仍然是一个指针,因此您可以用它调用 T*
重载。然而,在另一个方向上,模板推导将失败,因为 typename T::value_type
是一个非推导的上下文。因此 (2)
被认为是部分特化的,因此它被选为最佳可行候选者。没有歧义。