Clang 和 g++ 对运算符重载的处理方式不同?
Clang and g++ treat operator overload differently?
我正在使用 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 成功编译。
这样的期望合理吗?这是怎么回事?
您不能将临时对象绑定到非常量引用。在这种情况下 std::ostringstream()
创建一个临时对象并尝试绑定到 operator<<
的非常量引用参数
首先,标准为右值输出流 ([ostream.rvalue])
提供了一个包罗万象的 operator<<
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<<
。
其次,与模板一样,在这个函数模板的主体中,os << x
中 operator<<
的非限定查找是在模板定义上下文中完成的,它没有您的operator<<
可用。相反,您的重载必须由 ADL 找到,这反过来意味着它必须位于与 A
.
相同的命名空间中
你的第二个版本应该可以编译,并且在这两种情况下,编译器确实发现你的重载很好。问题在于 libstdc++ 的实现(归结为 return os << x;
)是不符合规范的,因为它假定 os << x
必须 return os
。没有这个要求。
编辑:libstdc++ 错误报告是here;它已在主干中得到修复,并且已将修复程序反向移植到 4.8 和 4.9 分支。
我正在使用 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 成功编译。
这样的期望合理吗?这是怎么回事?
您不能将临时对象绑定到非常量引用。在这种情况下 std::ostringstream()
创建一个临时对象并尝试绑定到 operator<<
首先,标准为右值输出流 ([ostream.rvalue])
提供了一个包罗万象的operator<<
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<<
。
其次,与模板一样,在这个函数模板的主体中,os << x
中 operator<<
的非限定查找是在模板定义上下文中完成的,它没有您的operator<<
可用。相反,您的重载必须由 ADL 找到,这反过来意味着它必须位于与 A
.
你的第二个版本应该可以编译,并且在这两种情况下,编译器确实发现你的重载很好。问题在于 libstdc++ 的实现(归结为 return os << x;
)是不符合规范的,因为它假定 os << x
必须 return os
。没有这个要求。
编辑:libstdc++ 错误报告是here;它已在主干中得到修复,并且已将修复程序反向移植到 4.8 和 4.9 分支。