0

Recently while reading blog on universal reference by scott meyers i came along statement that "if you can take the address of an expression, the expression is an lvalue." but is this really true

Suppose i have following code

class Test
{
};
int main()
{
   std::cout << "Address is " << &(Test()) << std::endl;
   Test() = Test();
   Test&& t = Test();
   return 0;
}

In above case Test() is temporary i.e rvalue and i am able to take address of that (with gcc we can use -fpremissive and with msvc it will compile directly) so with this we can say it is lvalue and also bcoz we can do Test() = Test() but since we can take rvalue reference to it so it should be rvalue.

So why we always say that if we can take address of variable then it is lvalue ?

PapaDiHatti
  • 1,841
  • 19
  • 26
  • For your second case, you could have a look at http://stackoverflow.com/questions/2145030/are-all-temporaries-rvalues-in-c. – Holt May 18 '16 at 10:08
  • Yes i am taking address of y but that is not compiling and that's the reason i m asking if y is lvalue why can't i take address of y – PapaDiHatti May 18 '16 at 10:30
  • Also assuming that Test() is lvalue then how i am able to take rvalue reference to it as Test&& t = Test(); is compiling properly – PapaDiHatti May 18 '16 at 10:49
  • A *variable* cannot be an lvalue; an lvalue is a kind of *expression*. (The name of a variable is an lvalue.) – Keith Thompson May 18 '16 at 23:47

2 Answers2

3

Your first code is incorrect because the declaration of z should be int*, this code compiles and works fine:

int x = 12;  // x is lvalue
int& y = x;  // y is lvalue reference
int *z = &y; // can take address of lvalue reference (address of the referenced)
assert(z == &x);

For your second example, Test() is actually a prvalue and you cannot take its address in a portable way as mentioned per the standard.

MSVC has extensions that allow you to take the address of prvalues, and GCC allows you to enable this kind of extension using -fpermissive:

Downgrade some diagnostics about nonconformant code from errors to warnings. Thus, using -fpermissive will allow some nonconforming code to compile.

This means that Scott Meyers is right and the compilers are wrong, at least in the question of conforming to the standard. Also, by passing -fpermissive you told gcc to be less strict, i.e. allow your non-conforming code to compile. To be completely conforming, you should always compile with -pedantic or -pedantic-errors (because just like MSVC, gcc also enables some language extensions by default).

Tamás Szelei
  • 23,169
  • 18
  • 105
  • 180
Holt
  • 36,600
  • 7
  • 92
  • 139
  • Thanks i have removed first portion since it was incorrect but based on your previous comments i am able to compile Test() =Test() without any extensions.So does that rvalue can also come on left hand side and then why 2=2 will not compile in c++ ? – PapaDiHatti May 18 '16 at 11:49
  • @Kapil My last comment was flawed (sorry), `rvalue` is somehow a bad name. `Test() = Test()` is basically `Test().operator=(Test())` and there is nothing wrong with calling a method on a `rvalue`. – Holt May 18 '16 at 12:02
0

Based on the comments from holt and since i have edited the question so i think right answer should be Test() in above context is rvalue and if we use standardized compiler this code will not compile so if your code is compiling it means either fpermissive flag is set in gcc or with msvc your settings allow you to get this working. Second line Test() = Test() is working because it is equivalent to Test().operator=() and we can call function from rvalue. Now third line is implicit since its an rvalue so we can have rvalue reference to this.

Hence with this example it proves that we can only take address of lvalues provided we are using standardized compiler.

All the credit for this question should go to holt as i have just written answer as people usually don't read comments and also bcoz i have edited the question

PapaDiHatti
  • 1,841
  • 19
  • 26