5

Is it permitted to declare a non-const reference as constexpr? Example code:

int x = 1;
constexpr int& r = x;

This is accepted by gcc and clang (I tried several current and past versions of both, back to C++11, and all accepted it). However I think it should not be accepted because C++14 [dcl.constexpr/9] says:

if a constexpr specifier is used in a reference declaration, every full- expression that appears in its initializer shall be a constant expression

and x is not a constant expression.

The language in the latest C++17 draft of [dcl.constexpr] changed and doesn't even mention constexpr references explicitly any more, I can't make head nor tail of what it is trying to say about them.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • 1
    Who said `x` isn't a constant expression? – T.C. Apr 21 '17 at 06:16
  • "`x` isn't a core constant expression" {{citation needed}} – T.C. Apr 21 '17 at 06:28
  • @T.C. [expr.const]/2 "`e` is a core constant expression unless the evaluation of `e` would evaluate one of the following: [...] an lvalue-to-rvalue conversion, unless it is applied to [cases that this code doesn't match]" – M.M Apr 21 '17 at 06:30
  • `x` is assigned a literal value, shouldn't that be good enough for the compiler to know it is compile-time known? – asimes Apr 21 '17 at 06:30
  • How does evaluating the expression `x` necessitate an lvalue-to-rvalue conversion on it? – T.C. Apr 21 '17 at 06:31
  • @T.C. I thought it was implied that it was ... apparently not. So `x` would instead be covered by /2.9 which I'm assuming it is intended to say that an id-expression denoting an object is a constant expression iff it was initialized with a constant expression. Not clear to me whether that sentence means "(a variable) or (data member of reference type)", or "(a variable or data member) of reference type" – M.M Apr 21 '17 at 06:40
  • The latter, of course. Before digging into the complicated C++1* rules, remember that this has been always been valid: `int x; template struct C {}; C c;` Something that can be used as a template argument must be a constant expression. – T.C. Apr 21 '17 at 07:06

1 Answers1

4

Assuming that x has static storage duration, the lvalue expression x is a perfectly valid constant expression.

If you use x in a context that requires a prvalue, which causes the lvalue-to-rvalue conversion to be applied to it, then the resulting prvalue expression - call it TO_RVALUE(x) - would not be a constant expression, for obvious reasons. But in the case of reference binding, there is no such conversion.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Does it depend on the initializer? (E.g. does `int x = rand();` still make `x` a constant expression?) – M.M Apr 21 '17 at 06:46
  • @M.M No. (Yes.) A lvalue constant expression merely designates the entity (basically, it's like its address). What it is initialized with is irrelevant, and need not even be known to the compiler (e.g., `extern int x;` is sufficient). – T.C. Apr 21 '17 at 07:03