Bernd said:
Can't follow what? That it's illegal, or that some compilers
accept it.
All g++-3.3.6, 4.2.1, and 4.3.0 make the first line in foo an
error and the second a warning without any special settings.
According to the standard, both are errors. The first was
allowed in very early versions of C++; it was found to cause
problems, and was banned sometime in the late 1980's (before the
standardization effort even began). I can understand compilers
in the early 1990's only giving a warning (so as not to break
existing code); I can even understand a compiler today having
options which would only make it a warning. But silently
accepting it, as Sun CC did? Something's wrong.
The second takes the address of an lvalue. That's never been
legal, not since K&R C. I can't understand any compiler not
making it a hard error.
(Note that the first can be made legal with a user defined
conversion to an lvalue in the class, and the second can be made
legal with a user defined operator&. Neither are present in the
example, however.)
The first line is the one that assigns reference to a
temporary to a non-const reference type, which cannot work.
Strictly speaking: neither line "assigns" anything. The first
line initializes a non-const reference with an rvalue; that's
forbidden by §8.5.3/5. The second takes the address of an
lvalue; that's forbidden by §5.3.1/2. (And it would also be an
initialization, rather than an assignment. Although in the case
of pointers, unlike references, the difference is neglible.)
The second line seems to have the same problem with const
pointer and non-const pointer at first.
liftim1.cc: In function ?void foo()?:
liftim1.cc:12: error: invalid initialization of non-const reference of
type ?A&? from a temporary of type ?B?
liftim1.cc:13: warning: taking address of temporary
A temporary object is not a const object by definition if
there is no const in the declaration.
Which isn't really relevant here.
The standard mandates that assigning a temorary to a non-const
reference is not allowed, but this decision is kind of
deliberate, because it would produce hard to detect errors
most of the time.
It's very deliberate, because it actually did produce hard to
detect errors a lot of times.
But taking the pointer is not the same es taking a reference.
Using that pointer could be problematic, especially
dereferencing, but the heuristical warning is the best one can
hope for when taking the address alone.
The standard says quite clearly: "The result of the unary &
operator is a pointer to its operand. The operand shall be an
lvalue or a qualified-id." (The "qualified-id" is for pointers
to members.) This is taken almost directly from C: "The operand
of the unary & operator shall be either a function designator,
the result of a [] or unary * operator, or an lvalue that
designates an object that is not a bit-field and is not declared
with the register storage-class specifier." (This is taken from
C99, which is the only C standard which I have available here.
"result of a [] or unary * operator" was definitely not present
in C90; for the rest, however, the text is basically unchanged
from C90, and if memory serves me right, K&R C.)
In sum, this has never, ever been legal, and I can't see the
slightest reason for a compiler to accept it. Interestingly
enough, in both Sun CC and g++, it actually depends on the type:
both compilers treat something like:
int* p = foo() ;
(where foo() returns an int) as an error, and SunCC behaves
differently depending on whether there is inheritance or a user
defined constructor. None of which makes any sense to me: it's
an error, it has always been an error, and there's not the
slightest justification for any compiler in the world to treat
it otherwise.