tags:

views:

389

answers:

7

§5.3.1 Unary operators, Section 3

The result of the unary & operator is a pointer to its operand. The operand shall be an lvalue or a qualified-id.

What exactly does "shall be" mean in this context? Does it mean it's an error to take the address of a temporary? I was just wondering, because g++ only gives me a warning, whereas comeau refuses to compile the following program:

#include <string>

int main()
{
    &std::string("test");
}

g++ warning: taking address of temporary

comeau error: expression must be an lvalue or a function designator

Does anyone have a Microsoft compiler or other compilers and can test this program, please? Thanks in advance.

+3  A: 

When the word "shall" is used in the C++ Standard, it means "must on pain of death" - if an implementation does not obey this, it is faulty.

anon
-1. Actually, this applies only to those statements of the form "the implementation shall do X". Statements of the form "the input code shall do X", it means "must on pain of diagnostic".
MSalters
@MSalters Must on pain of death issue a diagnostic.
anon
@MSalters And BTW, I've always thought it was dubious practice to downvote answers to a question you yourself are supplying an answer to.
anon
I don't see why. If you think an answer is incorrect, it should be downvoted whether or not you've written an answer on your own. I think we're mature enough to handle that, aren't we? Or do people really take the rep-race that seriously?
jalf
Look, the point of SO is to act as a repository of answers. There are usually multiple answers, so how do you (as a later reader) pick the sensible ones? Voting is intended to highlight the good ones. I answered _explicitly_ because I found the highest-voted one incorrect, and for that very same reason I downvoted it.
MSalters
@jalf I think it would be politer to point out the error (which MSalters has not done - my answer is perfectly correct) and wait for a correction before downvoting. That's what I try to do, anyway.
anon
Consider the "pain of death" statement again. If the requirement is on input code, your interpretation reads as a pain of death _for the code_, ie. the code _MUST NOT_ compile. This is factually untrue. The code may very well compile, with the only pain being a diagnostic.
MSalters
@MSalters I nowhere said and did not mean that the code "MUST NOT compile". Please don't put words into my mouth.
anon
MSalters
@MSalters To quote from your own answer: "So, in this particular case, a conformant compiler must give a diagnostic" - how does this contradict what I wrote?
anon
In fact, it says the argument could be a `qualified-id`. This wrongly includes some rvalue cases, i think: `struct A { enum { HAHA }; }; int main() { }`. It's a nonstatic member accessed using a qualified-id, so the standard gives it type "pointer to member of class A of type <unnamed-enum>". I think it should say "nonstatic data member or nonstatic member function", and say at the end "otherwise, the program is ill-formed.". Not sure tho...
Johannes Schaub - litb
A: 

I'm not a standards expert, but it certainly sounds like an error to me. g++ very often only gives a warning for things that are really errors.

Hans W
+1  A: 

It is permitted in MSVC with the deprecated /Ze (extensions enabled) option. It was allowed in previous versions of MSVC. It generates a diagnostic with all warnings enabled:

warning C4238: nonstandard extension used : class rvalue used as lvalue.

Unless the /Za option is used (enforce ANSI compatibility), then:

error C2102: '&' requires l-value

Hans Passant
A: 

&std::string("test"); is asking for the address of the return value of the function call (we'll ignore as irrelevant the fact that this function is a ctor). It didn't have an address until you assign it to something. Hence it's an error.

James Curran
You can of course take the address of function call return values, provided they are lvalues.
anon
But if you're calling a function, isn't that by definition an rvalue?
TMN
@TMN No - in C++ you can return a reference, which is an lvalue. That's how things like operator[] for std::vector work.
anon
@James Curran: Incorrect. This is not a function call. This is a *functional-style cast*. And you can take the adress of the result of a cast (as well as of the result of a function call) if it is an *lvalue*. A reference, for example, is always an lvalue.
AndreyT
A: 

The C++ standard is a actually a requirement on conformant C++ implementations. At places it is written to distinguish between code that conformant implementations must accept and code for which conformant implementations must give a diagnostic.

So, in this particular case, a conformant compiler must give a diagnostic if the address of an rvalue is taken. Both compilers do, so they are conformant in this respect.

The standard does not forbid the generation of an executable if a certain input causes a diagnostic, i.e. warnings are valid diagnostics.

MSalters
+3  A: 

The word "shall" in the standard language means a strict requirement. So, yes, your code is ill-formed (it is an error) because it attempts to apply address-of operator to a non-lvalue object.

However, the problem here is not an attempt of taking address of a temporary. The problem is, again, taking address of a non-lvalue. Temporary object can be lvalue or non-lvalue depending on the expression that produces that temporary or provides access to that temporary. In your case you have std::string("test") - a functional style cast to a non-reference type, which by definition produces a non-lvalue. Hence the error.

If you wished to take address of a temporary object, you could have worked around the restriction by doing this, for example

const std::string &r = std::string("test");
&r; // this expression produces address of a temporary

whith the resultant pointer remaining valid as long as the temporary exists. There are other ways to legally obtain address of a temporary object. It is just that your specific method happens to be illegal.

AndreyT
Johannes Schaub - litb
In fact, the Standard itself seems to misuse the term "temporary", if i'm not mistaken. It says that a temporary bound to a function return should be destroyed after the function returns. However, this means that `struct A { A return *this; } int i; }; int main() { A().ref().ref(); }` invokes undefined behavior, because after the first `ref()`, the object doesn't exist anymore. It misses to say that only such objects are considered, that haven't yet been bound to a reference (including the implicit object parameter).
Johannes Schaub - litb
A: 

I love passing stack-allocated anonymous variable references in MSVC - it's more of a functional programming paradigm and I consider it a great language feature. I don't like that warning ...

Chris
FredOverflow
Chris