Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this expression not a constant expression?

The expression b in this code shall be a core constant expression

int main()
{
    constexpr int a = 10;
    const int &b = a;
    constexpr int c = b; // here
    return 0;
}

since the standard says (8.20, paragraph 2 [expr.const] in n4700)

An expression e is a core constant expression unless the evaluation of e would evaluate one of the following expressions:

  • ...

  • an lvalue-to-rvalue conversion (7.1) unless it is applied to

    • ...

    • a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable subobject of such an object, or

First, the expression b in the above code is an lvalue (which is also a glvalue) since it's a reference, thereby being a variable (8.1.4.1, paragraph 1 [expr.prim.id.unqual]):

The expression is an lvalue if the entity is a function, variable, or data member and a prvalue otherwise; it is a bit-field if the identifier designates a bit-field (11.5).

Second, the object the variable b denotes is a, and it's declared with constexpr. However, gcc complains

./hello.cpp: In function ‘int main()’:
./hello.cpp:6:20: error: the value of ‘b’ is not usable in a constant expression
  constexpr int c = b;
                    ^
./hello.cpp:5:13: note: ‘b’ was not declared ‘constexpr’
  const int &b = a;

As far as I can tell, a reference is not an object, so the above bullet apparently suggests that a shall be declared with constexpr. Am I missing something? The reason why I don't agree with gcc is that gcc sees b as an object, thereby requiring it to be declared with constexpr. However, b is not an object!

like image 207
b1sub Avatar asked Dec 20 '17 15:12

b1sub


People also ask

What is a constant expression?

A constant expression is an expression that can be evaluated at compile time. Constants of integral or enumerated type are required in several different situations, such as array bounds, enumerator values, and case labels. Null pointer constants are a special case of integral constants.

How do you solve a constant expression required error in C++?

For example, if a program requires a “const”, but you're feeding it a “variable value”, which can be changed in the program or overwritten. So, use the keyword “const” before that variable to make it a constant and resolve the error.


1 Answers

One of the rules for core constant expressions is that we can't evaluate:

an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either

  • it is initialized with a constant expression or
  • its lifetime began within the evaluation of e;

b is an id-expression that refers to a variable of reference type with preceding initialization. However, it is initialized from a. Is a a constant expression? From [expr.const]/6:

A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints: [... ]

An entity is a permitted result of a constant expression if it is an object with static storage duration that is either not a temporary object or is a temporary object whose value satisfies the above constraints, or it is a function.

a is a glvalue core constant expression (it doesn't hit any of the restrictions in expr.const/2), however it is not an object with static storage duration. Nor is it a function.

Hence, a is not a constant expression. And b, as a result, isn't initialized from a constant expression and so can't be used in a core constant expression. And thus c's initialization is ill-formed as not being a constant expression. Declare a as a static constexpr int, and both gcc and clang accept the program.

C++, you magical beast.

like image 78
Barry Avatar answered Sep 29 '22 11:09

Barry