Compilando o código a seguir e obtendo o erro de type illegal
.
int main()
{
// Compilation error - switch expression of type illegal
switch(std::string("raj"))
{
case"sda":
}
}
Você não pode usar string em switch
ou case
. Por quê? Existe alguma solução que funcione bem para oferecer suporte a lógica semelhante à ativação de strings?
c++
string
switch-statement
yesraaj
fonte
fonte
QMetaEnum
Respostas:
A razão pela qual tem a ver com o sistema de tipos. C / C ++ não suporta realmente cadeias de caracteres como um tipo. Ele suporta a idéia de uma matriz de caracteres constante, mas na verdade não entende completamente a noção de uma string.
Para gerar o código para uma instrução switch, o compilador deve entender o que significa dois valores iguais. Para itens como ints e enums, essa é uma comparação pouco trivial. Mas como o compilador deve comparar 2 valores de string? Diferencia maiúsculas de minúsculas, insensibilidade, cultura, etc ... Sem uma percepção completa de uma string, isso não pode ser respondido com precisão.
Além disso, as instruções de opção C / C ++ geralmente são geradas como tabelas de ramificação . Não é tão fácil gerar uma tabela de ramificação para uma opção de estilo de string.
fonte
std::string
literais foram adicionados. É principalmente histórico. Mas um problema que vem à mente é que, com a maneira comoswitch
funciona atualmente, duplicadoscase
s devem ser detectados em tempo de compilação; no entanto, isso pode não ser tão fácil para seqüências de caracteres (considerando a seleção de localidade em tempo de execução e assim por diante). Suponho que algo assim deva exigirconstexpr
casos ou adicionar um comportamento não especificado (nunca algo que queremos fazer).std::string
valores ou mesmo umastd::string
matriz com char const (ou seja, usando o operador ==); não há razão técnica que impeça o compilador de gerar uma instrução switch para qualquer tipo que forneça esse operador. Isso abriria algumas questões sobre coisas como a vida útil dos rótulos, mas tudo isso é principalmente uma decisão de design de linguagem, não uma dificuldade técnica.Como mencionado anteriormente, os compiladores gostam de criar tabelas de pesquisa que otimizam
switch
instruções para o tempo próximo de O (1) sempre que possível. Combine isso com o fato de que a linguagem C ++ não possui um tipo de string -std::string
faz parte da Biblioteca Padrão, que não faz parte da linguagem em si.Vou oferecer uma alternativa que você pode querer considerar, eu a usei no passado com bons resultados. Em vez de alternar sobre a própria string, alterne o resultado de uma função hash que usa a string como entrada. Seu código será quase tão claro quanto alternar a string se você estiver usando um conjunto predeterminado de strings:
Existem várias otimizações óbvias que seguem o que o compilador C faria com uma instrução switch ... engraçado como isso acontece.
fonte
C ++
função hash constexpr:
fonte
operator ""
para tornar o código mais bonito.constexpr inline unsigned int operator "" _(char const * p, size_t) { return hash(p); }
E usá-lo comocase "Peter"_: break;
demonstraçãoAtualização do C ++ 11 aparentemente não @MarmouCorp acima, mas http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4067/Switch-on-Strings-in-C.htm
Usa dois mapas para converter entre as seqüências de caracteres e a enumeração de classe (melhor que a enumeração simples, porque seus valores têm escopo dentro dela e pesquisa inversa para obter boas mensagens de erro).
O uso de static no código do codeguru é possível com o suporte do compilador para listas de inicializadores, o que significa o VS 2013 plus. O gcc 4.8.1 estava bem com isso, não sei quanto tempo atrás seria compatível.
...
fonte
O problema é que, por razões de otimização, a instrução switch no C ++ não funciona em nada além de tipos primitivos, e você só pode compará-los com constantes de tempo de compilação.
Presumivelmente, o motivo da restrição é que o compilador é capaz de aplicar alguma forma de otimização compilando o código em uma instrução cmp e em um local em que o endereço é calculado com base no valor do argumento em tempo de execução. Como ramificações e loops não funcionam bem com CPUs modernas, isso pode ser uma otimização importante.
Para contornar isso, receio que você precise recorrer a declarações if.
fonte
std::string
e outros cidadãos em primeiro lugar no idioma e apoiá-los na instrução switch com um algoritmo eficiente.std::map
+ C ++ 11 padrão lambdas sem enumsunordered_map
para o potencial amortizadoO(1)
: Qual é a melhor maneira de usar um HashMap em C ++?Resultado:
Uso dentro de métodos com
static
Para usar esse padrão de maneira eficiente dentro das classes, inicialize o mapa lambda estaticamente, ou então você paga
O(n)
sempre para construí-lo do zero.Aqui, podemos nos safar da
{}
inicialização de umastatic
variável de método: Variáveis estáticas em métodos de classe , mas também poderíamos usar os métodos descritos em: construtores estáticos em C ++? Eu preciso inicializar objetos estáticos privadosEra necessário transformar a captura de contexto lambda
[&]
em um argumento, ou isso teria sido indefinido: const static auto lambda usado com captura por referênciaExemplo que produz a mesma saída que acima:
fonte
switch
declaração. A duplicação de valores de caso em umaswitch
instrução é uma falha no tempo de compilação. O usostd::unordered_map
silencioso aceita valores duplicados.Em C ++ e C, os switches funcionam apenas em tipos inteiros. Use uma escada if else. Obviamente, o C ++ poderia ter implementado algum tipo de declaração swich para strings - acho que ninguém achou que valesse a pena e concordo com eles.
fonte
Por que não? Você pode usar a implementação do switch com sintaxe equivalente e a mesma semântica. O
C
idioma não possui objetos e objetos de cadeias, mas cadeias de caracteresC
são cadeias terminadas nulas referenciadas pelo ponteiro. AC++
linguagem tem a possibilidade de criar funções de sobrecarga para comparação de objetos ou verificação da igualdade de objetos. ComoC
comoC++
é suficiente flexível para ter essa mudança para cordas paraC
a linguagem e para objetos de qualquer tipo que o apoio comparaison ou igualdade cheque deC++
linguagem. E os modernosC++11
permitem que essa implementação de switch seja eficaz o suficiente.Seu código será assim:
É possível usar tipos mais complicados, por exemplo,
std::pairs
ou quaisquer estruturas ou classes que suportem operações de igualdade (ou comarcas para o modo rápido ).Recursos
As diferenças Sintax com a mudança de idioma são
Para o
C++97
idioma usado pesquisa linear. ÉC++11
possível, de maneira mais moderna, usar aquick
pesquisa em árvore wuth em modo, onde a instrução de retorno no CASE não é permitida. AC
implementação do idioma existe onde aschar*
comparações de tipo e seqüência de caracteres terminadas em zero são usadas.Leia mais sobre esta implementação de switch.
fonte
Para adicionar uma variação usando o contêiner mais simples possível (não há necessidade de um mapa ordenado) ... Eu não me incomodaria com uma enumeração - basta colocar a definição do contêiner imediatamente antes do comutador, para que seja fácil ver qual número representa qual caso.
Isso faz uma pesquisa de hash no
unordered_map
e usa o associadoint
para conduzir a instrução switch. Deve ser bem rápido. Observe queat
é usado em vez de[]
, como eu fiz esse contêinerconst
. O uso[]
pode ser perigoso - se a sequência não estiver no mapa, você criará um novo mapeamento e poderá resultar em resultados indefinidos ou em um mapa em crescimento contínuo.Observe que a
at()
função lançará uma exceção se a string não estiver no mapa. Então, você pode querer testar primeiro usandocount()
.A versão com um teste para uma sequência indefinida é a seguinte:
fonte
Eu acho que a razão é que, em C, as strings não são tipos primitivos, como Tomjen disse, pensam em uma string como uma matriz de caracteres, então você não pode fazer coisas como:
fonte
Em c ++, as strings não são cidadãos de primeira classe. As operações de string são feitas através da biblioteca padrão. Eu acho que é essa a razão. Além disso, o C ++ usa a otimização da tabela de ramificação para otimizar as instruções de maiúsculas e minúsculas. Dê uma olhada no link.
http://en.wikipedia.org/wiki/Switch_statement
fonte
Em C ++, você pode usar apenas uma instrução switch em int e char
fonte
long
elong long
, o que não se tornaráint
. Não há risco de truncamento lá.fonte
Em muitos casos, você pode evitar trabalho extra, puxando o primeiro caractere da string e ativando-o. pode acabar precisando fazer uma troca aninhada no charat (1) se seus casos começarem com o mesmo valor. qualquer pessoa que esteja lendo seu código apreciaria uma dica, porque a maioria provavelmente tentaria apenas se-mais-se
fonte
Solução alternativa mais funcional para o problema do comutador:
fonte
Você não pode usar string no switch case.Only int & char são permitidos. Em vez disso, você pode tentar enum para representar a cadeia de caracteres e usá-la no bloco de casos do switch, como
Use-o na declaração swich case.
fonte
Os comutadores funcionam apenas com tipos integrais (int, char, bool etc.). Por que não usar um mapa para emparelhar uma string com um número e depois usá-lo com a opção?
fonte
Isso ocorre porque o C ++ transforma os switches em tabelas de salto. Ele executa uma operação trivial nos dados de entrada e salta para o endereço correto sem comparar. Como uma string não é um número, mas uma matriz de números, o C ++ não pode criar uma tabela de salto a partir dela.
(código da wikipedia https://en.wikipedia.org/wiki/Branch_table )
fonte
cmp
/jcc
implementação pode ser igualmente válida de acordo com o Padrão C ++.