两个运营商的一些奇怪的冲突<<
Some strange conflict of two operators <<
为什么下面的代码不编译?
#include <iostream>
namespace X
{
inline std::wostream & operator<<(std::wostream & stm, int a)
{
stm << L"int";
return stm;
}
}
namespace Y
{
class A
{
};
}
inline std::wostream & operator<<(std::wostream & stream, const Y::A & msg)
{
stream << L"A";
return stream;
}
namespace X
{
void f()
{
Y::A a;
std::wcout << a;
}
}
为什么要删除命名空间 X 中的operator <<
会使代码编译?尝试将其注释掉,例如:
namespace X
{
//inline std::wostream & operator<<(std::wostream & stm, int a)
//{
// stm << L"int";
// return stm;
//}
}
这些运算符之间的依赖关系是什么?
请参阅实时示例。
编辑1:
我唯一的猜测是,在使用它的同一命名空间中声明的运算符以某种方式隐藏了其他命名空间中的运算符,但我以前从未听说过......
编辑2:
实际上在我的项目中,第二个运算符位于命名空间 Z(但不是全局(中:
...
namespace Z
{
inline std::wostream & operator << (std::wostream & stream, const Y::A & msg)
{
stream << L"A";
return stream;
}
}
namespace X
{
void f()
{
using namespace Z;
Y::A a;
std::wcout << a;
}
}
这会导致相同的编译器错误。
此行为实际上是C++中预期的,以避免不同命名空间中的不同重载引入的意外行为。
这称为名称隐藏。 你可以在这里阅读一个非常好的答案:https://stackoverflow.com/a/1629074/182676
因此,不同命名空间中的重载将相互隐藏。
您可以通过使用以下using
使正确的重载对编译器可见来解决此问题:
Y::A a;
using Z::operator<<;
std::wcout << a;
注意:重载运算符的查找与其他注释/答案建议的类成员函数查找有很大不同。有关重载运算符的名称查找规则的介绍,请参阅此答案。
在第一个示例中,std::wcout << a
X::f()
中,名称查找会找到:
- 对左操作数的成员函数进行限定查找:
std::wostream
有一个成员函数operator<<
。 - 非限定查找:当前范围在命名空间
X
中,因此找到X::operator<<
,我们到此为止。此阶段仅在找不到名称时检查父命名空间。
参数 - 依赖查找:参数是
std::wcout
和Y::a
的,因此ADL命名空间是std
和Y
的。
因此,重载集包括:
- (QL( 所有成员函数
std::wostream::operator<<
。 - (UL( 所有免费功能
X::operator<<
。 - (ADL( 所有免费函数
std::operator<<
- (ADL(所有自由函数
Y::operator<<
(如果有的话,也会
(。
仅此而已。
这些都找不到参数类型Y::A
的匹配项,因此编译失败。
删除X::operator<<
时,非限定查找步骤在X
中找不到任何内容,因此它会递归地在父命名空间中查找。然后找到::operator<<
函数进入重载集,编译成功。
为了避免此问题,通常的过程是将用户定义类型的自由重载运算符放入与定义类型相同的命名空间中,因此在这种情况下,您将执行以下操作:
namespace Y
{
inline std::wostream & operator<<(std::wostream & stream, const A & msg) { .... }
}
然后 ADL 步骤会找到这个函数,即使非限定查找步骤也找到X::operator<<
。
在第二个示例中,using namespace Z;
的确切含义是:
在非限定名称查找期间,这些名称看起来就像是在最近的封闭命名空间中声明的,该命名空间同时包含 using-指令和指定的命名空间。
包含X
和Z
的最近的封闭命名空间是全局命名空间,因此这些名称的行为就像在非限定查找阶段的全局命名空间中一样。
因此,该过程与我对第一个案例的分析没有实质性区别,只有X::operator<<
是通过不合格的查找找到的。 同样,这将通过在Y
中包含所需的重载来修复,以便 ADL 找到它。
- 写入位置0x0000000C时发生访问冲突
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- GL_SHADERSTORAGE_BUFFER位置是否与其他着色器位置冲突
- 使用cmake从源代码构建MySQL连接器/C++失败(与以前的声明冲突)
- 引发异常:读取访问冲突**dynamicArray**为0x1118235.发生
- 如何防止clang格式在流运算符调用之间添加换行符<<
- <<操作员在下面的行中工作
- C++LinkedList问题.数据类型之间存在冲突?没有匹配的构造函数
- 链表中写入访问冲突的未知原因
- C++中的openCV Mat访问冲突
- 如何使 std::sort 在 std::swap 和我的命名空间的模板化交换之间没有名称冲突?
- C++尝试深度复制唯一指针时出现内存访问冲突
- 错误:使用通用引用的声明冲突
- 如何解决GTest和LibTorch联动冲突
- 两个运营商的一些奇怪的冲突<<
- 如何在多个线程中创建 QSql数据库连接时防止名称冲突
- C++ 中动态二维数组的访问冲突
- 从嵌套循环中的 std::list 中删除将返回访问冲突
- C++17 十六进制浮点文字单精度后缀冲突?