-2

I have the following code that demonstrate my problem:

int main(void)
{
    const int ci = 42;
    constexpr int j = ci; 
}

The above program compiles fines. But I'm expecting it to be ill-formed.

First, the initializer 42 is an integral constant expression converted to int via identity conversion; then, the converted expression is a core constant expression: ([const.expr]/9)

An integral constant expression is an expression of integral or unscoped enumeration type, implicitly converted to a prvalue, where the converted expression is a core constant expression.

Second, I claim that the expression E = ci is not usable in constant expression because it's not constant-initialized (i.e, it's variable has no static duration) even though the expression ci is potentially-constant variable (i.e, it's variable of const-qualified integral type). So you can't apply the rule [expr.const]/4 because it requires the object to be potentially-constant as well as constant-initialized:

A constant-initialized potentially-constant variable V is usable in constant expressions at a point P if V's initializing declaration D is reachable from P and ..

So per my understanding, for variable ci to be constant-initialized, it has to have a static duration as well as a constant-expression initializer.

Assuming my understanding is correct so far, I will continue.

In the initialization of j, an lvalue-to-rvalue conversion is performed on the glvalue ci; but this conversion is applied to a non-volatile glvalue that refers to an object ci that is not usable in constant expressions. So I'm expecting the program to be ill-formed because the expression E evaluates an lvalue-to-rvalue conversion and neither rule in [expr.const]/(5.9) permits it. Am I correct? What I'm missing/conflating here? Am I missing any wording?

As a sidenote, in C++17, the rule regarding this point is more restricted and clear at least for me:

an lvalue-to-rvalue conversion unless it is applied to

  • (2.7.1) a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression [..]

It's definitely clear to me that the wording is applied here and (2.7.1) is satisfied. But the wording regarding this point specifically is changed in C++20: The term usable "usable in constant expressions" appears since C++20 per my search. Note that, if possible, I need a C++20 answer.

mada
  • 1,646
  • 1
  • 15
  • const is allowed by the standard to turn into constexpr if the initializer is a constant expression like 42. – digito_evo Sep 15 '22 at 11:59
  • @digito_evo - _"const is allowed by the standard to turn into constexpr"_ Where the standard says that? – mada Sep 15 '22 at 12:01
  • From [cppreference](https://en.cppreference.com/w/cpp/language/constant_expression#Usable_in_constant_expressions) Integral type are special with `const` which can be "equivalent" to `constexpr`. – Jarod42 Sep 15 '22 at 12:16
  • See 18:34 at https://youtu.be/tA6LbPyYdco from CppCon 2021. – digito_evo Sep 15 '22 at 12:20
  • These days you wonder is C++ has turned more to a high-end brain teaser than to a programming language. –  Sep 15 '22 at 12:22
  • @Jarod42 - I'm just confused. Please tell me, a constant-initialized object can have a non-static duration? – mada Sep 15 '22 at 12:24
  • @Jarod42 - "_From cppreference Integral type are special with const which can be "equivalent" to constexpr._" Is that because cppreference said: _"the variable is a constexpr variable **OR** it is a constant-initialized variable of .."_? – mada Sep 15 '22 at 12:26
  • Watch that section of the video I have linked above. I think you should be convinced since that guy is from the standard committee. – digito_evo Sep 15 '22 at 12:28
  • `const int ci = 42;` is mostly equivalent to `constexpr int ci = 42;`. its lifetime is as regular variable: until end of scope. – Jarod42 Sep 15 '22 at 12:29
  • @Jarod42 both of them have automatic storage duration and are usually fetched from the binary of the program and loaded onto the call stack at runtime. That's how X84 handles these variables. – digito_evo Sep 15 '22 at 12:31
  • @Jarod42 - So I still need to invoke [expr.const]/5 in order to whether the expression `ci` (in my example) is core constant expression or not. Right? – mada Sep 15 '22 at 12:32
  • `const int ci = random();` would not be equivalent to `constexpr int ci = random();/*Wrong*/`. – Jarod42 Sep 15 '22 at 12:36
  • @Jarod42 - So I still need to invoke [expr.const]/5. Right? – mada Sep 15 '22 at 12:38
  • @Jarod42 - `constexpr int j = ci; the expression `ci` is just an expression and it's required to know whether it core constant expression or not. Right? – mada Sep 15 '22 at 12:44
  • "The expression `E = ci` is not usable in constant expression" - how is that relevant? The _assignment expression_ `E = ci` is not used in `constexpr int j = ci;`. The latter is a definition. It's a definition that contains an initializer expression, but the initializer expression is just the `ci` part. – MSalters Sep 15 '22 at 13:01
  • @MSalters - `E` is refer to [expr.const]/5: _"An expression `E` is a core constant expression unless the evaluation of E"_. where the expression `E` is `ci` in my example. – mada Sep 15 '22 at 13:09
  • @MSalters - `E = ci` is not an assignment expression as you think. I'm not using any assignments in any example. `E = ci` equivalent `E is ci` – mada Sep 15 '22 at 13:11
  • @MSalters - Can you help me to understand, if possible? – mada Sep 15 '22 at 13:12
  • @YvesDaoust - My brain can't accept that `ci` in the initialization `constexpr int j = ci;` is usable in constant expression. – mada Sep 15 '22 at 13:13
  • @John: You've written it like the initializer expression is something like `const int ci = 42; int E; constexpr j = (E=ci);`. The grammar allows that, but I don't think that is what you're trying. – MSalters Sep 15 '22 at 13:14
  • @MSalters, No that's not what I meant. Thanks for your reply. – mada Sep 15 '22 at 13:15

2 Answers2

2

I claim that the expression E = ci is not usable in constant expression because it's not constant-initialized (i.e, it's variable has no static duration)

constant-initialized is defined in [expr.const]/2. It is not the same as "has constant initialization", and does not care about storage duration.

T.C.
  • 133,968
  • 17
  • 288
  • 421
1

By the definition of "constant-initialized" ([expr.const]/2), the following is constant-initialized because 42 is a constant expression.

int ci = 42;

By the definition of "potentially-constant" ([expr.const]/3), the following is potentially-constant because the variable is a const-qualified integral type.

const int ci;

If you have both of these at function scope, then you have a variable that is usable in constant expressions from the point of definition until the end of the variable's scope (special case of [expr.const]/4).

JaMiT
  • 14,422
  • 4
  • 15
  • 31
  • In my example: `constexpr int j = ci;` Is `ci` is usable in constant expression? – mada Sep 15 '22 at 13:19
  • 1
    @John In your example (`const int ci = 42;`), do you have both `const int ci` and `int ci = 42;` as parts of the definition of `ci`? – JaMiT Sep 15 '22 at 13:21
  • Are you even look at my example? – mada Sep 15 '22 at 13:22
  • My example is as shown above: it doesn't have static or global variables – mada Sep 15 '22 at 13:23
  • @John: Neither definition cares about being static or global. – Nicol Bolas Sep 15 '22 at 13:24
  • "If you have both of these at function scope," Sorry I read it as file scope, not function scope. – mada Sep 15 '22 at 13:27
  • So please tell me, `const int j = ci;` Is `ci` usable in constant expression? – mada Sep 15 '22 at 13:28
  • _"do you have both const int ci and int ci = 42; as parts of the definition of ci?"_ No if I understood what you mean correcly – mada Sep 15 '22 at 13:29
  • 1
    @John: "*So please tell me, const int j = ci; Is ci usable in constant expression?*" Why are you talking about the initialization of `j`? That has no bearing on whether `ci` is usable in a constant expression; that's defined by how `ci` is declared and initialized. – Nicol Bolas Sep 15 '22 at 13:31
  • 1
    @John Are you unable to find the text `const int ci` in the text `const int ci = 42;`? Try looking at the first 12 characters of the latter and comparing them to the 12 characters of the former. Same for the text `int ci = 42;` except now compare the last 12 characters. Not asking for any interpretation or programming skill at this point, just the ability to compare character-by-character. – JaMiT Sep 15 '22 at 13:36
  • @NicolBolas - Thanks. I think I'm misreading the standard regarding this point. So in the initialization `const int ci = 42;`, the expression `ci` _is_ usable in constant expressions because it's a potentially-constant constant-initialized variable. Am I correct now? – mada Sep 15 '22 at 13:38
  • `const int ci = 42;`, the expression `ci` is usable in constant expressions because it's a potentially-constant constant-initialized variable. Am I correct? – mada Sep 15 '22 at 13:49