考虑以下代码:
#include <iostream>
namespace ns1
{
struct A
{
};
template <class T>
std::ostream& operator << (std::ostream& os, const T& t)
{
return os << "ns1::print" << std::endl;
}
}
namespace ns2
{
template <class T>
std::ostream& operator << (std::ostream& os, const T& t)
{
return os << "ns2::print" << std::endl;
}
void f (const ns1::A& a)
{
std::cout << a;
}
}
int main()
{
ns1::A a;
ns2::f (a);
return 0;
}按照标准,编译失败并出现“歧义重载错误”。
但是为什么呢?A的“home”命名空间中的“同样好”的运算符肯定应该优先吗?有没有什么合理的理由不去做呢?
发布于 2016-02-26 01:38:39
如果你想让namespace A中的重载成为首选,那么你必须在其中添加一些东西来使它变得更好。比方说,让它不再是一个模板:
namespace ns1
{
std::ostream& operator<<(std::ostream&, const A& );
}否则,如果一个名称空间中的函数模板与另一个名称空间中的函数模板完全相同,那么就没有任何概念性的理由来解释为什么两者更受欢迎。毕竟,为什么A的名称空间中的函数模板会比f的名称空间中的函数模板“更好”呢?f的实现者不是“更清楚”吗?仅仅依靠函数签名可以回避这个问题。
发布于 2016-02-26 04:22:11
如果仔细阅读编译器错误,就会发现歧义错误不是发生在ns1和ns2中的operator<<版本之间,而是发生在ns1的operator<<(os, const char*)实例化和namespace std的完全相同的重载之间。后者正被std::ostream上的ADL所拖累。
最好的方法是使用@Barry的建议,并在名称空间ns1中取消operator<<的模板化,但也要将所有与ns1::A相关的功能(如f(A))添加到同一名称空间中:
#include <iostream>
namespace ns1
{
struct A {};
std::ostream& operator << (std::ostream& os, const A& t)
{
return os << "ns1::print" << std::endl;
}
void f (const A& a)
{
std::cout << a;
}
}
int main()
{
ns1::A a;
f(a); // rely on ADL to find ns1::operator<<(os, A)
}命名空间ns1随后通过ADL充当class A的更广泛的接口。
https://stackoverflow.com/questions/35634091
复制相似问题