mardi 29 mars 2016

"no match" and "cannot bind lvalue" errors while overloading `operator<<` with `std::wostream` and `std::string`

I've got an error while overloading std::wostream::operator<<() for std::string. Here is the minimal test case illustrating my problem:

#include <string>
#include <sstream>

inline std::wostream &operator<<(std::wostream &os, const std::string &)
{
    return os;
}

class FakeOstream{};

namespace mynamespace {

class FakeClasse1 {
    friend inline FakeOstream &operator<<(FakeOstream &out, const FakeClasse1 &) { 
        return out; 
    }
};

class FakeClasse2 {
    friend inline FakeOstream &operator<<(FakeOstream &out, const FakeClasse2 &)  { 
        return out; 
    }
};

void test()
{
    auto mystring = std::string{u8"mystring"};
    std::wostringstream s;
    s << mystring;
}

} // namespace mynamespace

The code can be compiled and executed here: http://cpp.sh/9emtv

As you can see here, there is an overload for operator<< with std::wostream and std::string. The two fake classes are empty apart from the declaration of an operator<< with FakeOstream and themselves. The test() function instantiate an std::wostringstream and feed it a std::string. The fake fake classes and test function are in a namespace.

This code yields the following error on cpp.sh:

 In function 'void mynamespace::test()':
25:10: error: cannot bind 'std::basic_ostream<wchar_t>' lvalue to 'std::basic_ostream<wchar_t>&&'
In file included from /usr/include/c++/4.9/istream:39:0,
                 from /usr/include/c++/4.9/sstream:38,
                 from 2:
/usr/include/c++/4.9/ostream:602:5: note: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = wchar_t; _Traits = std::char_traits<wchar_t>; _Tp = std::basic_string<char>]'
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
     ^

When using directly g++ (version 5.3.0 from MSYS2), a no match error is also displayed:

./tmpbug.cpp: In function 'void mynamespace::test()':
./tmpbug.cpp:25:7: error: no match for 'operator<<' (operand types are 'std::wostringstream {aka std::__cxx11::basic_ostringstream<wchar_t>}' and 'std::__cxx11::basic_string<char>')
     s << mystring;
       ^
In file included from C:/Appli/msys64/mingw64/include/c++/5.3.0/istream:39:0,
                 from C:/Appli/msys64/mingw64/include/c++/5.3.0/sstream:38,
                 from ./tmpbug.cpp:2:
C:/Appli/msys64/mingw64/include/c++/5.3.0/ostream:628:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = wchar_t; _Traits = std::char_traits<wchar_t>; _Tp = std::__cxx11::basic_string<char>] <near match>
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
     ^
C:/Appli/msys64/mingw64/include/c++/5.3.0/ostream:628:5: note:   conversion of argument 1 would be ill-formed:
./tmpbug.cpp:25:10: error: cannot bind 'std::basic_ostream<wchar_t>' lvalue to 'std::basic_ostream<wchar_t>&&'
     s << mystring;
          ^
In file included from C:/Appli/msys64/mingw64/include/c++/5.3.0/istream:39:0,
                 from C:/Appli/msys64/mingw64/include/c++/5.3.0/sstream:38,
                 from ./tmpbug.cpp:2:

As far as I know, all the parts of the example are necessary for the errors to appear. If I comment out the namespace, the fake classes or just one of the operator<< in the fake classes, the code compile just fine. Moreover, if I just move one of the fake classes or the test function outside of the namespace, the code will also compile just fine.

Additionnally, I tried compiling this example on clang 3.7 by using the compiler from http://cppreference.com, and the code seems to compile without problems.

Is there a problem with my code or is this a GCC bug ? If this is a GCC bug, is there a workaround ?

Aucun commentaire:

Enregistrer un commentaire