TL; DR
A única maneira de declarar uma variável com um inicializador ou algum objeto não trivial dentro de um caso é introduzir um escopo de bloco usando {}
ou outra estrutura de controle que tenha seu próprio escopo como um loop ou instrução if .
Detalhes sangrentos
Podemos ver que os casos são apenas instruções rotuladas como os rótulos usados com uma instrução goto ( isso é abordado no esboço do padrão C ++ seção 6.1 Instrução rotulada ) e podemos ver na seção 6.7
parágrafo 3 que pular uma declaração não é permitido em muitos casos , incluindo aqueles com uma inicialização:
É possível transferir para um bloco, mas não de uma forma que ignore as declarações com a inicialização. Um programa que salta 87 de um ponto onde uma variável com duração de armazenamento automático não está no escopo para um ponto onde está no escopo é malformado, a menos que a variável tenha tipo escalar, tipo de classe com um construtor padrão trivial e um destruidor trivial, uma versão cv qualificada de um desses tipos, ou uma matriz de um dos tipos anteriores e é declarada sem um inicializador (8.5).
e fornece este exemplo:
void f() {
// ...
goto lx; // ill-formed: jump into scope of a
ly:
X a = 1;
// ...
lx:
goto ly; // OK, jump implies destructor
// call for a followed by construction
// again immediately following label ly
}
Observe que existem algumas sutilezas aqui, você pode pular uma declaração escalar que não possui uma inicialização, por exemplo:
switch( n )
{
int x ;
//int x = 10 ;
case 0:
x = 0 ;
break;
case 1:
x = 1 ;
break;
default:
x = 100 ;
break ;
}
é perfeitamente válido ( exemplo ao vivo ). Obviamente, se você quiser declarar a mesma variável em cada caso , cada um deles precisará de seu próprio escopo, mas funciona da mesma maneira fora das instruções switch , de modo que não deve ser uma grande surpresa.
Quanto à justificativa para não permitir o salto além da inicialização, o relatório de defeito 467, embora abranja uma questão ligeiramente diferente, fornece um caso razoável para variáveis automáticas :
[...] variáveis automáticas, se não inicializadas explicitamente, podem ter valores indeterminados ("lixo"), incluindo representações de trap, [...]
É provavelmente mais interessante olhar para o caso em que você estende um escopo dentro de um switch sobre vários casos. Os exemplos mais famosos disso são provavelmente o dispositivo de Duff, que seria mais ou menos assim:
void send( int *to, const int *from, int count)
{
int n = (count + 7) / 8;
switch(count % 8)
{
case 0: do { *to = *from++; // <- Scope start
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while(--n > 0); // <- Scope end
}
}