Does each expression in C++ have a non-reference type

Viewed 230

Hi i am reading about expression in C++ and across the statement

Statement 0.0

Each expression has some non-reference type

The quoted statement is from en.cppreference.com/w/cpp/language/value_category. Check line 2 at the top of the page.

Now i took some examples to understand what this means. For example:

int i = 100; // this expression has type int
int &j = i; // this expression has type int or int&?

My confusion is that i know that j is a reference to int that is j is int& but according to the quoted statement every expression has a non-reference type will imply that int &j = i; has type int. Is this correct? Other examples that i am getting confused about:

int a[4] = {2,4,4,9};
a[3]; // will this expression be int& type or int type?

Now in the statement a[3]; i know that a is a array lvalue and so a[3] returns a lvalue reference to the last element. But getting confused about will the quoted statement 0.0 imply that this whole expression a[3]; be a int or an int& type?

Here is another example:

b[4]; // Here assume that b is an array rvalue. So will this expression has  type int&& or int?

So my question is that does something similar happen for pointers also? Meaning do we have a similar statement(0.0) for pointers also?

int x = 34;
int *l = &x; // will this expression have type int* or int?

I now that here l is a pointer to int(compound type). If there is no similar statement for pointers then what is the need for this statement for references? That is why do we strip off the reference part only?

3 Answers
int i = 100; // this expression has type int
int &j = i; // this expression has type int or int&?

These statements are not expressions at all. These are declararions. They do contain sub expressions 100 and i, both of which have the type int. If you used the id expression j after this declaration, the type of that expression would be int.

So my question is that does something similar happen for pointers also?

No. Pointers are non-reference types, and something similar doesn't happen to expressions with pointer types.

why do we strip off the reference part only?

This is simply how the language works. It allows us treat objects and references to objects identically.

This is part of why you dont need to (nor can you) explicitly use an indirection operator to access the referred object, unlike needing to use an indirection operator to access a pointed object.


Here is the actual language rule (from latest standard draft):

[expr.type]

If an expression initially has the type “reference to T” ([dcl.ref], [dcl.init.ref]), the type is adjusted to T prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.

Expression : An expression is made up of one or more operands and yields a result when it is evaluated.

Note the wording " when it is evaluated ".

Examples of expressions are: the literal 4, or some variable n. Again note that the expression is not yet evaluated and so have no result. Also you can create more complicated expressions from an operator and one or more operands. For example 3 + 4*5 is an unevaluated-expression. An expression with two or more operators is called a compound expression.

Each expression in C++ is either a rvalue or a lvalue.

Expression Statement: Statements end with a semicolon. When we add a semicolon to an expression, it becomes an expression statement. The affect of this is that this causes the expression to be evaluated and its result discarded at the end of the statement. So for example the literal 5 is an expression but if you add a semicolon ; after it then we will have a expression statement. Also the result of this expression will be discarded at the end of the expression statement. Lets looks at another example, cout << n; is a expression statement as a whole. It consists of the following expressions:

1. expression `cout`
2. expression 'n'

And it consists of one operator << and a null statement ; This whole statement will cause a side-effect which will be the printing of value of n on the screen.

Update:

Example 1: std::cout << n; will have a side-effect of printing the value of n on the screen but more importantly it will also have a resulting value which will be the object std::cout which is discarded at the end of the statement.

Example 2: int i(20 + 1); consists of 3 things:

  1. type : int
  2. identifier i
  3. expression 20 + 1

Example 3: float p; This has no expression. This is just variable definition. Also called declaration statement.

Example 4: float k = 43.2; This has an expression at the right hand side which is 43.2, a type float and an identifier k.

Example 5: i = 43;. This is an expression statement. There are two expressions and one operator here. The result is the variable i.

Example 6: int &r = i;. This is a declaration statement since it consists of the expression i on the right hand side. Also on the left hand side we have a type(int) and a declarator(&r). Since it is not an expression statement there will be no value that will be discarded.

Example 7: int *p = &i; This is an declaration statement since it consists of the expression i on the right hand side. Also on the left hand side we have a type(int) and a declarator(*p). Since it is not an expression statement there will be no value that will be discarded.

Example 8: i = a < b ? a : b; This is an expression statement. Here the expressions are:

  1. the left hand side variable i

  2. the variable a on the right hand side

  3. the variable b on the right hand side

Also there is one condition in the middle(a < b ). If the condition evaluates to true then the result of this will be the variable a and b otherwise.

C++ expressions can have forms like j+0 or (j). These expressions definitely have type int.

To simplify the grammar, the name of a variable by itself is also usable as an expression. If we didn't have this rule, in the grammar we'd have a lot of variable-or-expression constructs. But it means that the expression j has the same type as the expression j+0, namely int.

Related