This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 113d. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-03-20


2005. Incorrect constexpr reference initialization requirements

Section: 7.7  [expr.const]     Status: NAD     Submitter: David Krauss     Date: 2014-09-18

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 (9.2.6 [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 7.7 [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.)

Rationale (November, 2014):

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