13

Deferencing pointer leads to using the value of the object indirectly. But I've never really understood what does the "using" means. I started to think the question until my compiler yield an error for the following code

int i = 0, *pi = &i;
decltype(*pi) c; // error: 'c' declared as reference but not initialized.

I looked at the error for a very long time and searched some questions I can only give out the following arguments. I don't know if they are correct or not.

Arguments 1:

1) *p is an expression that is not a variable (or non-variable expression)

2) dereferencing pointer expression yields a reference, we are in fact using a reference to access the value of the object

Arguments 2:

the dereferencing expression only for which decltype returns a reference, it is not a general case

Please points out any incorrectness or inaccurate descriptions of the above arguments.

SLN
  • 4,772
  • 2
  • 38
  • 79
  • 3
    Here's a technique that can almost always be used to get the compiler to tell you the type of an expression: https://wandbox.org/permlink/GBApa0x01iwP7K9a (try to access a non-existent member) – Justin Jan 22 '18 at 19:02
  • 3
    Seems to me to be an excellent opportunity to dig into [the standard](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4700.pdf) for an answer (you might learn another thing or two as well while browsing through it). – Jesper Juhl Jan 22 '18 at 19:03
  • Related voodoo: https://stackoverflow.com/questions/13202289/remove-reference-in-decltype-return-t-instead-of-t-where-t-is-the-decltype – user4581301 Jan 22 '18 at 19:09

3 Answers3

18

Dereferencing a pointer yields an lvalue expression of the pointed-to type designating the object or function pointed to. It does not yield a reference.* *pi is an lvalue of type int.

decltype (with an exception not relevant here) reports both an expression's type and its value category, the latter being encoded with reference types. Since *pi is an lvalue, it's encoded as an lvalue reference type, so decltype(*pi) is int &: int for the type, & for the value category.

Expressions never have reference type because any referenceness is adjusted away "prior to any further analysis".


* This isn't a merely technical distinction: per the direction of core issue 232 and core issue 453, there are valid dereference expressions you can write where binding its result to a reference would cause undefined behavior.

T.C.
  • 133,968
  • 17
  • 288
  • 421
5

To answer your title question: as T.C. answered too, no. Expressions never have reference type. Given an int a; int &b = a;, both the expression a and the expression b have type int, and both expressions are lvalues.

1) *p is an expression that is not a variable (or non-variable expression)

Correct.

2) dereferencing pointer expression yields a reference, we are in fact using a reference to access the value of the object

Dereferencing a pointer gives an lvalue, which decltype changes into an lvalue reference.

the dereferencing expression only for which decltype returns a reference, it is not a general case

I'm not entirely sure what you mean here. If you mean that when decltype doesn't produce a reference, having a declaration decltype(...) c; without an initialiser can be valid, then yes, indeed. If you mean that aside from dereferenced pointers, decltype never produces a reference type, then no. For instance,

int a;
decltype((a)) b; // not okay - decltype((a)) is int & because (a) is not the name of the
                 // variable, and the expression (a) is an lvalue
decltype(a) c;   // okay - decltype(a) is int because a is the name of the variable
decltype(+a) d;  // okay - decltype(+a) is int because the +a is a prvalue of type int
3

As a matter of fact, standard says following in 8.5.2.1:

The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points. If the type of the expression is “pointer to T”, the type of the result is “T”.

So it is not the reference, but decltype() gives you something which actually has a representation in the C++ types system, and reference is the closest thing to it.

SergeyA
  • 61,605
  • 5
  • 78
  • 137