4

As we know that we can not initialize a variable in any of the case in switch, unless it is the last case of the respective switch, as initialization of variables does require the definition to execute at runtime (since the value of the initializer must be determined at that point),

BUT

We also know that a constexpr variable will get initialized or get replaced in the code with its value during the compilation process itself.

So I tried the below code i.e., initializing a constexpr variable Z in case 2 (which is the not the last case of the switch) but I am getting an error stating as:

crosses initialization of ‘constexpr const int z’ 24 |
constexpr int z{ 4 }; // illegal: initialization is not allowed if subsequent cases exist

May someone please clarify the reason behind this error?

Thanking you in Advance!

#include <iostream>

int main()
{
switch (1)
{
    int y; 
    
    case 1:
        y = 4; 
        break;

    case 2:
        constexpr int z{ 4 }; // ERROR
        break;

    case 3:
        y=5;
        break;
}
return 0;
}
wohlstad
  • 12,661
  • 10
  • 26
  • 39
Akshay J R
  • 111
  • 4
  • Reopened. The dupe target refers to non-constexpr variables, I that reasoning doesn't really apply to constexpr ones. – HolyBlackCat Dec 22 '22 at 08:37

2 Answers2

3

According to the c++ reference for the switch statement

Because transfer of control is not permitted to enter the scope of a variable, if a declaration statement is encountered inside the statement, it has to be scoped in its own compound statement.

This means that you can actually initialize a local variable, constexpr or not, as long as it is inside a scope. For example, a small modification of your code does compile:

#include <iostream>

int main()
{
switch (1)
{
    int y; 
    
    case 1:
        y = 4; 
        break;

    case 2:
        {
            constexpr int z{ 4 }; // No more ERROR
            break;
        }
    case 3:
        y=5;
        break;
}
return 0;
}

Check it live on Coliru.

The switch statement jumps to a matching case very much like a goto statement. Then, like the goto statement, it would be unclear what would happen if, by jumping to a given line, you "skip" the declaration/initialization of the variable.

Consider the following example:

int main()
{
    goto jump;
    int i = 1;
    
jump:

}

This does not compile, because in executing the jump, the compiler does not know what to do the variable i. Notice that, if you did not have the jump, it would possible to use the variable i after the jump label. But what if you just "skip" the initialization? Then, the code is malformed. The switch statement, essentially does a goto and because of that it has the same limitations. The fact the the variable you declare is a constexpr does not change this limitation.

francesco
  • 7,189
  • 7
  • 22
  • 49
  • OP already knows why non-constexpr variables are not allowed, and asks why constexpr initialization doesn't remove this limitation. – HolyBlackCat Dec 22 '22 at 09:16
1

The initialization of a variable with automatic storage duration happens when control transfers over it, regardless of it is a constexpr variable or not.

Consider the following code (if initializing a constexpr variable was allowed in the body of a switch):

void f(const int*);
switch (cond) {
case 1:
    constexpr int z{ 4 };
    f(&z);
    break;
case 2:
    f(&z);
    break;
}

Even though z is a constexpr variable, a compiler would still put it on the stack to pass its address to f, and it's value on the stack would be assigned 4 at runtime. But what about the case 2? The compiler will allocate z on the stack when it enters the switch, but logically the initializer will only be "ran" if it enters the first case.

You can't "initialize" a constexpr variable at compile time because it will be placed on the stack. Whether it is eliminated entirely and all occurrences of it replaced is an optimization (which isn't always possible if its address is taken).

Artyer
  • 31,034
  • 3
  • 47
  • 75