tags:

views:

307

answers:

2

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?

+3  A: 

My guess is that EnhSimOutput& operator<< (setw& p); passes by non-const reference, but the value 26 is "const" in the sense that it cannot be modified. Try setting it to EnhSimOutput& operator<< (const setw& p);

or try

int nNumber = 26;  
enh::eout << enh::setw(nNumber);
unistudent
-1, because the issue has nothing to do with 26 being a literal. The problem is that 'enh::setw(number)' is a temporary, and therefore can't be bound to a non-const reference.
Luc Touraille
+11  A: 

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.

Johannes Schaub - litb
Changing the operator to a const reference fixes the problem gracefully. Thanks for the info about rvalues.I have no idea why the code compiled for anyone else. The project is intended for Windows... maybe they're all using a *cough* non-compiliant compiler. No idea.
Matt Gallagher
litb: I think you mean "reference-to-const" in your sentence "Also, if you go by that, the parameter can't have called non-const member functions on it, because it's a reference-to-nonconst."
j_random_hacker
Matt: older versions of MS Visual C++ would incorrectly bind temporaries to ref-to-non-const. I think this was fixed in MSVC++ 2005.
j_random_hacker
j_random_hacker, thanks for the pointer
Johannes Schaub - litb