Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When can't an object be converted to a reference?

Tags:

c++

reference

gcc

I want to compile the following line of code from http://code.google.com/p/enhsim:

enh::eout << enh::setw(26);

gcc gives the following error:

error: no match for 'operator<<' in 'enh::eout << enh::setw(26)'

But the EnhSimOutput class (of which enh::eout is an instance) does declare:

EnhSimOutput& operator<< (setw& p);

This problem goes away if I implement a version of the operation that accepts the object by value:

EnhSimOutput& operator<< (setw p);

or if I create the enh::setw object as a local, i.e.:

enh::setw wValue(26);
enh::eout << wValue;

My question is this: why does gcc not select the "by-reference" version of the operator to begin with?

The developers who wrote this code clearly made it compile, yet default gcc refuses to do it. Why is there a difference between an object declared separately as a local variable and a local created inline?

like image 932
Matt Gallagher Avatar asked Jan 15 '09 03:01

Matt Gallagher


1 Answers

The value enh::setw(26); is an rvalue . Actually, temporaries like that are rvalues. Rvalues have special properties. One of them is that their address can't be taken (&enh::setw(26); is illegal), and they can't generally bind to references to non-const (some temporaries can bind to references to non-const, but these undergo special rules: Calling member functions on temporary objects and catching exception objects by reference to non-const. In the latter case, the temporary even is an lvalue).

There are two kind of expressions: lvalues that denote objects (that in turn may store an value) or functions, and rvalues which are meant to represent values read out of an object or represented by temporaries, numeral literals and enumerator constants. In C++03, to be able to pass such values to a function that accepts its value by-reference, there is a rule that they can be accepted by reference-to-const: setw const& p would accept it. That is, you would have to declare your operator like this:

EnhSimOutput& operator<< (setw const& p);

That's a bit unfortunate, because you can't disambiguate constant lvalues (objects you created on the stack using const enh::setw e(26); for example) and non-const or const rvalues (like enh::setw(26); which is a non-const temporary). Also, if you go by that, the parameter can't have called non-const member functions on it, because it's a reference-to-const. For that reason, C++1x, the next C++ version, introduce a new kind of reference, so-called rvalue-references which fixes that.


The Microsoft Visual C++ compiler binds rvalues to references to non-const, but gives out a warning when doing that (you have to use at least warning level 4 for it to show up). That's unfortunate, because problems rise up when porting to other compilers that are more strict in Standard compliance.

like image 140
Johannes Schaub - litb Avatar answered Sep 28 '22 00:09

Johannes Schaub - litb