请考虑以下代码:
#include <iostream>
namespace A {
struct Mine {};
template <typename T1, typename T2>
void foo(T1, T2)
{
std::cout << "A::foo" << std::endl;
}
}
namespace B {
template <typename T>
void foo(T, T)
{
std::cout << "B::foo" << std::endl;
}
}
using namespace A;
using namespace B;
// or with the same effect:
//using A::foo;
//using B::foo;
int main()
{
A::Mine a;
foo(a, a);
}
程序打印b::foo
而不是a::foo
。 为什么它使用b::foo
而不是a::foo
?
想象以下情况:您的库提供了一个名称空间a
,其他一些库提供了名称空间b
,其中包含一个与您的库同名的函数模板foo
。 通常情况下,没有问题,因为可以使用限定调用或依赖于参数的查找来选择正确的版本。 但是,如果用户使用using
声明将a::foo
和b::foo
引入同一作用域,则非限定调用并不含糊,但可能选择了错误的函数。
有没有一种方法更喜欢a::foo
而不是b::foo
,因为根据参数依赖的查找,应该选择a::foo
? 在这种情况下你有什么建议?
它实际上在做正确的事情。 原因如下。
namespace A {
struct Mine {};
template <typename T1, typename T2>
void foo(T1, T2)
{
std::cout << "A::foo" << std::endl;
}
}
当有2个不同(或相同)类型的参数传递时,将匹配上述代码。 因为您定义了不同的T1
和T2
(但它们也可以是相同的)。 但函数调用是
foo(a, a);
具有相同类型的两个参数。 现在在命名空间b
中定义了一个方法foo
,该方法具有两个相同类型的参数,如下所示
namespace B {
template <typename T>
void foo(T, T)
{
std::cout << "B::foo" << std::endl;
}
}
因此,来自命名空间b
的方法是匹配的,因为两个签名是不同的。
尝试添加以下代码
namespace C {
template <typename T>
void foo(T, T)
{
std::cout << "B::foo" << std::endl;
}
}
最终将出现编译器错误,指定方法定义中存在歧义,然后必须使用a::foo(a,a)
或您希望使用的任何名称空间手动解析foo的作用域。