Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error when casting temporary object to non-const reference

Tags:

c++

clang++

Here is a reproducible example taken from question about using temporary stringstream object:

#include <sstream>                     
#include <string>
#include <iostream>

using namespace std;

std::string transform(std::string);

int main()
{
    int i{};
    cout << transform( static_cast<stringstream &>(stringstream() << i).str() );
}

When trying to compile with clang version 9.0.0 under MacOS High Sierra I got following error:

$ clang++ -std=c++11 x.cc -c
x.cc:12:24: error: non-const lvalue reference to type 'basic_stringstream<...>' cannot bind to a temporary of type 'basic_stringstream<...>'
    cout << transform( static_cast<stringstream &>(stringstream() << i).str() );
                       ^                           ~~~~~~~~~~~~~~~~~~~
1 error generated.

When g++ 9.2.0 is used on same machine (also on Linux) everything compiles fine.

Seems that changing cast from stringstream & to const stringstream & or to stringstream && solves problem.

The question is if this is compiler bug or maybe clang is more strict about some standard rules?

like image 360
Krzysztof Avatar asked Dec 13 '19 15:12

Krzysztof


1 Answers

Yes, I think that is a bug in libc++.

According to [ostream.rvalue] there is an overload:

template<class charT, class traits, class T>
  basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>&& os, const T& x);

But libc++ implements this similar to:

template <class _Stream, class _Tp>
enable_if_t</*...*/, _Stream&&>
operator<<(_Stream&& __os, const _Tp& __x)
{
    // ...
}

The implementation makes this overload a better candidate than the in-class operator<< of ostream in overload resolution if a stream rvalue is used with <<, while the signature in the standard wouldn't be, and it also returns a rvalue reference, when it should return a lvalue reference. It also returns a reference of same type as was passed to it, while it should return a reference to its ostream base class, according to the standard quote.

The rvalue reference can not be bound to a non-const lvalue reference, hence the error.

The bug has already been reported here and there is an open LWG issue regarding the behavior here, which seems to suggest that in the future the standard might be adjusted to mandate libc++'s current behavior.

like image 72
walnut Avatar answered Oct 29 '22 18:10

walnut