Badmanchild
Badmanchild

Reputation: 1020

Clang and g++ treat operator overload differently?

I am using C++14 (-std=c++1y on both g++ 4.9.1 and clang 3.5).

To start, here is Exhibit A (where the Foo namespace exists):

#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;
}

Both Clang and g++ barf on this, although for different reasons.


Exhibit B (where there is no Foo namespace):

#include <iostream>
#include <sstream>

struct A
{};

void operator<<(std::ostream &os, A const &a)
{}

int main()
{
    A a;

    std::ostringstream() << a;

    return 0;
}

g++ still barfs, but Clang successfully compiles.

Is this reasonable to expect? What's going on here?

Upvotes: 1

Views: 264

Answers (2)

T.C.
T.C.

Reputation: 137425

First, the standard supplies a catchall operator<< for rvalue output streams ([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

(There's also a matching operator>> for rvalue input streams - see [istream.rvalue].)

This is the operator<< that gets called.

Second, as is usual for templates, in the body of this function template, the unqualified lookup for operator<< in os << x is done in the template definition context, which doesn't have your operator<< available. Instead, your overload must be found by ADL, which, in turn, means that it must be in the same namespace as A.

Your second version should compile, and in both cases the compiler did find your overload just fine. The problem is that libstdc++'s implementation (which boils down to return os << x;) is non-conforming, because it assumes that os << x must return os. There's no such requirement.

Edit: The libstdc++ bug report is here; it has since been fixed in trunk and the fix has been backported to the 4.8 and 4.9 branches.

Upvotes: 1

Neil Kirk
Neil Kirk

Reputation: 21803

You are not allowed to bind a temporary object to a non-const reference. In this case std::ostringstream() creates a temporary object and tries to bind to the non-const reference parameter of operator<<

Upvotes: 0

Related Questions