Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why `constexpr const int &a = 1;` failed in block scope?

N4527 7.1.5[dcl.constexpr]p9

A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, that call shall be a constant expression (5.20). Otherwise, or if a constexpr specifier is used in a reference declaration, every full-expression that appears in its initializer shall be a constant expression.

5.20[expr.const]p5

A constant expression is either a glvalue core constant expression whose value refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value is an object where, for that object and its subobjects:

— each non-static data member of reference type refers to an entity that is a permitted result of a constant expression, and

— if the object or subobject is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object (5.7), the address of a function, or a null pointer value.

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.

void foo(){
    constexpr const int &a = 1;//error
    constexpr static const int &b = 1;//ok in gcc 5.1.0 and clang 3.8.0

}

Question: Why constexpr const int &a = 1; failed in block scope?

like image 970
stackcpp Avatar asked Jul 20 '15 15:07

stackcpp


1 Answers

This is covered in cwg defect report 2005: Incorrect constexpr reference initialization requirements which says (emphasis mine):

Consider an example like:

  constexpr int f() { return 5; } // function must be constexpr
  constexpr int && q = f();       // but result is not constant
  constexpr int const & r = 2;    // temporary is still not constant
  int main() {
    q = 11;                       // OK
    const_cast< int & >( r ) = 3; // OK (temporary object is not ROMable)

    constexpr int && z = 7;       // Error? Temporary does not have static storage duration?
  }

A constexpr reference must be initialized by a constant expression (7.1.5 [dcl.constexpr] paragraph 9), yet it may refer to a modifiable temporary object. Such a temporary is guaranteed static initialization, but it's not ROMable.

A non-const constexpr reference initialized with an lvalue expression is useful, because it indicates that the underlying storage of the reference may be statically initialized, or that no underlying storage is required at all.

When the initializer is a temporary, finding its address is trivial. There is no reason to declare any intent the computation of its address. On the other hand, an initial value is provided, and that is also required to be a constant expression, although it's never treated as a constant.

The situation is worse for local constexpr references. The initializer generates a temporary when the declaration is executed. The temporary is a locally scoped, unique object. This renders constexpr meaningless, because although the address computation is trivial, it still must be done dynamically.

C++11 constexpr references required initialization by reference constant expressions, which had to “designate an object with static storage duration or a function” (C++11 5.20 [expr.const] paragraph 3). A temporary with automatic storage duration granted by the reference fails this requirement.

C++14 removes reference constant expressions and the static storage requirement, rendering the program well-defined with an apparently defeated constexpr specifier. (GCC and Clang currently provide the C++11 diagnosis.)

Suggested resolution: a temporary bound to a constexpr reference should itself be constexpr, implying const-qualified type. Forbid binding a constexpr reference to a temporary unless both have static storage duration. (In local scope, the static specifier fixes the issue nicely.)

The response is that this is already forbidden by 5.20 paragraph 4:

This issue is already covered by 5.20 [expr.const] paragraph 4, which includes conversions and temporaries in the analysis.

like image 139
Shafik Yaghmour Avatar answered Sep 28 '22 08:09

Shafik Yaghmour