我正在使用 C++14(-std=c++1y 在 g++ 4.9.1 和 clang 3.5 上)。
首先,这是附件 A(存在 Foo 命名空间的地方):
#include <iostream>
#include <sstream>
namespace Foo
{
struct A
{};
}
void operator<<(std::ostream &os, Foo::A const &a)
{}
int main()
{
Foo::A a;
std::ostringstream() << a;
return 0;
}
Clang 和 g++ 都对此感到厌恶,尽管出于不同的原因。
图表 B(没有 Foo 命名空间):
#include <iostream>
#include <sstream>
struct A
{};
void operator<<(std::ostream &os, A const &a)
{}
int main()
{
A a;
std::ostringstream() << a;
return 0;
}
g++ 仍然 barfs,但 Clang 成功编译。
这样的期望合理吗?这是怎么回事?
最佳答案
首先,标准提供了一个包罗万象的东西 operator<<
对于右值输出流 ([ostream.rvalue])
template <class charT, class traits, class T> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>&& os, const T& x);
Effects:
os << x
Returns:
os
(右值输入流也有匹配的 operator>>
- 参见 [istream.rvalue]。)
这是 operator<<
被调用。
其次,与模板一样,在这个函数模板的主体中,对 operator<<
的非限定查找在 os << x
是在模板定义上下文中完成的,它没有你的 operator<<
可用的。相反,您的重载必须由 ADL 找到,这反过来意味着它必须位于与 A
相同的命名空间中。 .
您的第二个版本应该可以编译,并且在这两种情况下,编译器确实发现您的重载很好。问题是 libstdc++ 的实现(归结为 return os << x;
)是不符合标准的,因为它假定 os << x
必须返回 os
.没有这样的要求。
编辑:libstdc++ 错误报告是 here ;它已在 trunk 中得到修复,并且已将修复程序反向移植到 4.8 和 4.9 分支。
关于c++ - Clang 和 g++ 对运算符重载的处理方式不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29234258/