views:

43

answers:

1

I have the following function

void AddNodeValue(XMLNode& node, std::string& value);

I want to use it like this:

document.AddNodeValue(modvalue,"modvalue");

and the compiler complains:

error C2664: 'void XML::XMLDocument::AddNodeValue(XML::XMLNode &,std::string &)' : cannot convert parameter 2 from 'const char [9]' to 'std::string &'
        A reference that is not to 'const' cannot be bound to a non-lvalue

I don't get why that is wrong?

Compiler: VS2003

+11  A: 

Your function needs to take const std::string& for you to use it like that.

C++ has a rule that an rvalue (in your case, a temporary std::string which is created from the string literal) can be bound with a const reference, but not a non-const reference.

As far as I know, this restriction isn't due to any fundamental implementation problem, since temporary values can be modified in other ways. But a function which takes a non-const reference is assumed to do so because its main purpose is to modify that argument. It doesn't usually make a lot of sense to do that with a temporary, so possibly banning it catches errors far more than it prevents people doing something worthwhile. Anyway, not all rvalues are temporaries: some are literals which really cannot be modified.

If you can't change the function AddNodeValue, then you can work around it:

std::string valstr("modvalue");
document.AddNodeValue(modvalue, valstr);
// valstr might have changed, check the documentation of AddNodeValue
Steve Jessop
The limitation basically exists to enforce the reference semantics. Reference is meant to be used with valid and persistent objects. Sure you can create an invalid reference by returning a reference to local value but that is a semantic error.
Let_Me_Be
@Let_Me_Be: right (assuming by "reference" you mean "non-const reference" - obviously const references are not meant to be used only with persistent objects). The next question, then, is *why* non-const references are meant to be used with valid and persistent objects, and AFAIK it's because it usually doesn't make a lot of sense to modify objects which aren't. C++0x provides a new kind of reference for objects which are valid but not persistent, which is nice for those occasions when it does make sense to modify such objects.
Steve Jessop
@Steve Yes, C++0x provides l-value references. The whole point of reference (internally is still a pointer) is that it is heavily limited (by being bound to some existing object, non-null, etc...). Therefore much more interesting optimizations can be provided by the compiler.
Let_Me_Be
@Let_Me_Be: right, but nothing you have said is any different for const and non-const references, so nothing you have said can possibly account for the rule that one can be bound to an rvalue, and the other cannot. The explanation of that lies elsewhere, and that's what I'm (I admit) guessing at. Whether references are "still pointers" internally is an implementation detail, and the situations where good optimizations are possible with references are precisely the situations where there will *not* be any pointer under the covers.
Steve Jessop
@Steve For const this rule doesn't matter. You can only read from a constant therefore it doesn't matter if it stops existing after the command.
Let_Me_Be