我正在使用C ++ 14(g ++ 4.9.1和clang 3.5上的-std = c ++ 1y)。
首先,这是图表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成功编译。
这是否合理?这里发生了什么?
答案 0 :(得分:1)
首先,该标准为rvalue输出流([ostream.rvalue])提供了一个cat operator<<
template <class charT, class traits, class T> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>&& os, const T& x);
效果:
os << x
返回:
os
(对于右值输入流,还有匹配的operator>>
- 请参阅[istream.rvalue]。)
这是被调用的operator<<
。
其次,与模板一样,在此函数模板的正文中,operator<<
中os << x
的非限定查找是在模板定义上下文中完成的,该模板定义上下文中没有operator<<
可用。相反,您的重载必须由ADL找到,这反过来意味着它必须与A
位于同一名称空间中。
你的第二个版本应该编译,在这两种情况下编译器确实发现你的重载就好了。问题是libstdc ++的实现(归结为return os << x;
)是不符合的,因为它假定os << x
必须返回os
。没有这样的要求。
编辑:libstdc ++错误报告为here;它已被固定在行李箱中,并且修复程序已被移植到4.8和4.9分支机构。
答案 1 :(得分:0)
不允许将临时对象绑定到非const引用。在这种情况下,std::ostringstream()
创建一个临时对象并尝试绑定到{const operator<<