Is f() lvalue?

M

Michael Ovetsky

Consider:

int g(){int b=1; return b;}

int main()
{
int d=2;
g()=d;
}


gcc compiler fails to compile it with 'non-lvalue in assignment' error
message, which I would expect.

However the following code happily compiles and executes:

struct A {int a;};
A f(){A b={1}; return b;}

int main()
{
A c ={2};
f()=c;
}


Does it mean that f() is lvalue if f returns struct or class object, but
not lvalue if f returns built-in type or incorrect implementation of
C++ standard by gcc is one to blame?

Thanks,

Michael
 
M

marco.wahl

int g(){int b=1; return b;}
struct A {int a;};
A f(){A b={1}; return b;}

int main()
{
A c ={2};
f()=c;
}
Does it mean that f() is lvalue if f returns struct or class object, but
not lvalue if f returns built-in type ....?

Yes, I think so.

I think a returned object is a lvalue (some say: value with location).
Obviously the returned object must have a location.
The int return-value of g is not a lvalue. It's just 1.
 
A

Andrey Tarasevich

Michael said:
Consider:

int g(){int b=1; return b;}

int main()
{
int d=2;
g()=d;
}


gcc compiler fails to compile it with 'non-lvalue in assignment' error
message, which I would expect.

However the following code happily compiles and executes:

struct A {int a;};
A f(){A b={1}; return b;}

int main()
{
A c ={2};
f()=c;
}


Does it mean that f() is lvalue if f returns struct or class object, but
not lvalue if f returns built-in type or incorrect implementation of
C++ standard by gcc is one to blame?

There's nothing wrong with the compiler. In both cases the returned
object is not an lvalue. The difference between the two is that in the
first case you are using built-in assignment operator and in the second
case you are using user-defined assignment operator (which in this case
is provided by the compiler as 'A& A::eek:perator=(const A&)').

The built-in assignment operator requires an lvalue on the left-hand
side. That's why you get the error message.

The user-defined assignment operator has no such requirement and the
code compiles fine.
 
M

Michael Ovetsky

There's nothing wrong with the compiler. In both cases the returned
object is not an lvalue. The difference between the two is that in the
first case you are using built-in assignment operator and in the second
case you are using user-defined assignment operator (which in this case
is provided by the compiler as 'A& A::eek:perator=(const A&)').

It still seems to me that gcc considers function call that returns
structure an lvalue.

The following code won't compile with "non-lvalue in unary `&'"
message.

int g(){int b=1; return b;}
int main()
{
&g();
}

However the following code will compile (albeit with "taking address
of temporary" warning)and execute:

struct A {int a;};
A f(){A b={1}; return b;}
int main()
{
&f();
}

I don't think that gcc uses user-defined A* operator&() in this case,
it just takes address of an object.

Michael Ovetsky
 
T

Tom Widmer

It still seems to me that gcc considers function call that returns
structure an lvalue.

The following code won't compile with "non-lvalue in unary `&'"
message.

int g(){int b=1; return b;}
int main()
{
&g();
}

However the following code will compile (albeit with "taking address
of temporary" warning)and execute:

The code is not well-formed, and the compiler is conforming in that it
outputs a diagnostic as required by the standard.
struct A {int a;};
A f(){A b={1}; return b;}
int main()
{
&f();
}

I don't think that gcc uses user-defined A* operator&() in this case,
it just takes address of an object.

Right, but the code isn't legal, since f() is an rvalue. You could
make it legal by explicitly overloading operator&, so you're back to
calling a member function on an rvalue, which is perfectly legal.

Tom
 
A

Andrey Tarasevich

Michael said:
...
It still seems to me that gcc considers function call that returns
structure an lvalue.

No, it doesn't.
The following code won't compile with "non-lvalue in unary `&'"
message.

int g(){int b=1; return b;}
int main()
{
&g();
}

However the following code will compile (albeit with "taking address
of temporary" warning)and execute:

struct A {int a;};
A f(){A b={1}; return b;}
int main()
{
&f();
}

I don't think that gcc uses user-defined A* operator&() in this case,
it just takes address of an object.

The second example is also ill-formed. You are right, in this case the
built-in operator '&' is used. And it is used illegally, since the
result of 'f' is not an lvalue.

GCC compiler implements a moderately popular language extension that
allows this code to compile and issues a warning to inform you about
that fact. It is a little surprising that GCC still compiles this code
in '-ansi -pedantic' mode (although issuing a warning is already enough
to satisfy the standard requirement concerning diagnostic messages).
Comeau Online compiler rejects the code with an error message.
 
J

James Dennett

Michael said:
Consider:

int g(){int b=1; return b;}

int main()
{
int d=2;
g()=d;
}


gcc compiler fails to compile it with 'non-lvalue in assignment' error
message, which I would expect.

However the following code happily compiles and executes:

struct A {int a;};
A f(){A b={1}; return b;}

int main()
{
A c ={2};
f()=c;
}


Does it mean that f() is lvalue if f returns struct or class object, but
not lvalue if f returns built-in type or incorrect implementation of
C++ standard by gcc is one to blame?

It's an rvalue (not an lvalue) in either case, but you *can*
assign to an rvalue of class type (because assignment in that
case is just syntactic sugar for a call to the operator=
member function, and member functions can be used on rvalues).

This is one reason why in some situations it makes sense to
return UDT values as consts, whereas that is nonsensical for
builtin types.

-- James
 
A

Alberto Barbati

Michael said:
Does it mean that f() is lvalue if f returns struct or class object, but
not lvalue if f returns built-in type or incorrect implementation of
C++ standard by gcc is one to blame?

gcc is conformant, but the reason is not the one you describe.

First of all, §3.10/5 clearly says that "The result of calling a
function that does not return a reference is an rvalue." So f() returns
an rvalue in both cases (basic type and class type).

It's true that §5.17/1 says "[Assigment operators] requires a modifiable
lvalue as their left operand" but that statement only applies to the
built-in assignment operator, i.e. it's true only for basic types. For
class types §5.17/4 takes precedence: "Assignment to objects of a class
is defined by the copy assignment operator (12.8, 13.5.3)"

Because of §13.5.3, when f() is of class type f() = expr is interpreted
as f().operator=(expr). Here's the quirk: you *can* invoke a member
function even on an rvalue. Thus the expression f() = expr is legal.

I know that it's not very intuitive, but that's how it is. A sometimes
useful idiom is to return a const T instead of a T, as in that case the
compiler won't be able to call operator= because it operates only on
non-const objects.

HTH,

Alberto
 
A

Arijit

GCC is right. What happens is in case of struct, the struct's assignment
operator (implicitly defined) gets called. So, the line f()=c actually
reads: c.operator =(f()); which is okay and compiles.

BTW, if I used a C compiler for this, will f()=c compile ?

-Arijit
 
B

Ben Hutchings

Michael Ovetsky wrote:
However the following code happily compiles and executes:

struct A {int a;};
A f(){A b={1}; return b;}

int main()
{
A c ={2};
f()=c;
}


Does it mean that f() is lvalue if f returns struct or class object, but
not lvalue if f returns built-in type or incorrect implementation of
C++ standard by gcc is one to blame?

Neither. There is no prohibition against calling non-const members of
rvalues of class-type, so in general you can assign to them. For this
reason some authors recommend qualifying return types with 'const' if
they are class-types.
 
A

Andrey Tarasevich

There's nothing wrong with the compiler. In both cases the returned
object is not an lvalue. The difference between the two is that in the
first case you are using built-in assignment operator and in the second
case you are using user-defined assignment operator (which in this case
is provided by the compiler as 'A& A::eek:perator=(const A&)').

The built-in assignment operator requires an lvalue on the left-hand
side. That's why you get the error message.

The user-defined assignment operator has no such requirement and the
code compiles fine.
 
B

Balog Pal

gcc compiler fails to compile it with 'non-lvalue in assignment' error
message, which I would expect.
However the following code happily compiles and executes:
struct A {int a;};
A f(){A b={1}; return b;}
f()=c;

Does it mean that f() is lvalue if f returns struct or class object, but
not lvalue if f returns built-in type or incorrect implementation of

Return A from f() is rvalue. The rules allow member funcitons called on a
rvalue. A::eek:perator = is a member funcion, so the code and the compiler is
correct.

You can return const A to avoid such assignment, or calling other nonconst
member functions.
 
G

Graeme Prentice

GCC is right. What happens is in case of struct, the struct's assignment
operator (implicitly defined) gets called. So, the line f()=c actually
reads: c.operator =(f()); which is okay and compiles.

BTW, if I used a C compiler for this, will f()=c compile ?

Not it would not compile in C. A modifiable lvalue is required as the
left hand operand of the assignment operator.

Try it here
http://www.comeaucomputing.com/tryitout/

struct A {int a;};
struct A f(){struct A b={1}; return b;}

int main()
{
struct A c ={2};
f()=c;
}

Graeme
 
M

Marlene Miller

Alberto Barbati said:
[...]
It's true that §5.17/1 says "[Assigment operators] requires a modifiable
lvalue as their left operand" but that statement only applies to the
built-in assignment operator, i.e. it's true only for basic types. For
class types §5.17/4 takes precedence: "Assignment to objects of a class
is defined by the copy assignment operator (12.8, 13.5.3)"

Because of §13.5.3, when f() is of class type f() = expr is interpreted
as f().operator=(expr). Here's the quirk: you *can* invoke a member
function even on an rvalue. Thus the expression f() = expr is legal.
[...]

Also,

§3.10/2 "An lvalue refers to an object or function. Some rvalue
expressions--those of class or cv-qualified class type--also refer to
objects. 47)"

Footnote 47) "Expressions such as an invocations of constructors and of
functions that return a class type refer to objects, and the implementation
can invoke member functions upon such objects, but the expressions are not
lvalues."
 
S

Sam

operator (implicitly defined) gets called. So, the line f()=c actually
reads: c.operator =(f()); which is okay and compiles.
c.operator = (f());?
OR
f().operator = (c); ?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,184
Messages
2,570,973
Members
47,530
Latest member
jameswilliam1

Latest Threads

Top