Clang和g ++对运算符重载有何不同?

时间:2015-03-24 13:44:10

标签: c++ namespaces operator-overloading rvalue

我正在使用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成功编译。

这是否合理?这里发生了什么?

2 个答案:

答案 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<<

的非const引用参数