重载解决规则C++缺陷
A flaw in C++ overload resolution rules?
请考虑以下代码:
#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"命名空间中的"同样好"的运算符应该优先吗?有什么合乎逻辑的理由不这样做吗?
如果您希望首选
namespace A
中的重载,则必须向其添加一些内容以使其实际上更好。比如说,通过使其不是模板:
namespace ns1
{
std::ostream& operator<<(std::ostream&, const A& );
}
否则,实际上没有概念上的理由来说明为什么一个命名空间中的函数模板比另一个命名空间中的函数模板更可取,如果两者完全相同。毕竟,为什么 A
命名空间中的函数模板会比 f
命名空间中的函数模板"更好"?f
的实施者难道不会"知道得更好"吗?仅依靠函数签名可以回避此问题。
如果你仔细阅读编译器错误,歧义错误不是在ns1
和ns2
的operator<<
版本之间,而是在ns1
的operator<<(os, const char*)
实例化和namespace std
完全相同的重载之间。后者被ADL拖入std::ostream
。
最好的方法是使用 @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
的更广泛接口。
相关文章:
- 当基类是依赖类型时,这是一个缺陷吗
- 在这个函数中是有缺陷的,因为取消引用 null 是无效的,所以我想更改代码
- 这是 basic.def.odr 部分的缺陷吗?
- 代码在 CodeSignal 中工作不正确。不确定这是否是我的代码缺陷
- 当子类需要在 c++ 中相互包含时,继承有缺陷
- 与纯 V8 相比,NodeJS 是否有任何性能缺陷或显著开销?
- 无法打印完整的二叉搜索树,因为我从最低节点向后迭代的逻辑有缺陷
- 为什么在解雇方面没有seg缺陷?unique_ptr
- 将 std::vector<char> 转换为字符* 会导致字符缺陷
- OpenGL 缺陷 - 不需要的插值
- 这个危险指针示例是否因为 ABA 问题而存在缺陷?
- 这是 std::get ( const<T> std::p air<const T, U>& ) 由于 const T 而无法编译的C++缺陷吗?
- clang实现char8_t的方式是否存在缺陷,或者标准的某个黑暗角落是否禁止优化?
- 关于模板参数推理的看似有缺陷的段落?
- 尝试在C++中"blur"矩阵;有缺陷的算法或代码?
- C++图形初始化错误(语法或丢失文件缺陷?
- 链接列表,我的逻辑有缺陷
- 模板<类型名...>与模板不匹配<typename>是缺陷吗?
- 可理解的种族条件错误导致安全缺陷
- 我的二叉树插入逻辑的缺陷在哪里