Pregunta

Quiero usar switch-case en mi programa pero el compilador me da este error:

switch expression of type 'QString' is illegal

¿Cómo puedo utilizar el switch declaración con un QString?

Mi código es el siguiente:

bool isStopWord( QString word )
{
bool flag = false ;

switch( word )
{
case "the":
    flag = true ;
    break ;
case "at" :
    flag = true ;
    break ;
case "in" :
    flag = true ;
    break ;
case "your":
    flag = true ;
    break ;
case "near":
    flag = true ;
    break ;
case "all":
    flag = true ;
    break ;
case "this":
    flag = true ;
    break ;
}

return flag ;
}
¿Fue útil?

Solución

¿Cómo puedo utilizar la declaración de cambio con un QString?

No puedes.En lenguaje C++ switch La declaración solo se puede utilizar con tipos integrales o enum.Puedes poner formalmente un objeto de tipo clase en un switch declaración, pero eso simplemente significa que el compilador buscará una conversión definida por el usuario para convertirla a tipo integral o enumeración.

Otros consejos

Puede crear una QStringList antes de la iteración, así:

QStringList myOptions;
myOptions << "goLogin" << "goAway" << "goRegister";

/*
goLogin = 0
goAway = 1
goRegister = 2
*/

Entonces:

switch(myOptions.indexOf("goRegister")){
  case 0:
    // go to login...
    break;

  case 1:
    // go away...
    break;

  case 2:
    //Go to Register...
    break;

  default:
    ...
    break;
}

No es posible cambiar directamente las cadenas en C++.Sin embargo, es posible en Qt usando QMetaEnum como se muestra aquí: Q_ENUM y cómo encender una cuerda

Para hacer eso, primero declarar una enumeración con el cuerdas para ser utilizadas en cajas de interruptores como nombre del enumerador en su declaración de clase.Luego agregue la enumeración a los metadatos con Q_ENUMS para que el programa busque más tarde.

#include <QMetaEnum>

class TestCase : public QObject
{
    Q_OBJECT
    Q_ENUMS(Cases)        // metadata declaration

public:
    explicit Test(QObject *parent = 0);

    enum Cases
    {
        THE, AT, IN, THIS // ... ==> strings to search, case sensitive
    };

public slots:
    void SwitchString(QString word);
};

Luego en el .cpp El archivo implementa el cambio necesario después de convertir la cadena al valor correspondiente con .

La comparación distingue entre mayúsculas y minúsculas, por lo que si desea una búsqueda que no distinga entre mayúsculas y minúsculas, primero convierta la cadena de entrada a mayúsculas/minúsculas.También puedes realizar otras transformaciones necesarias en la cadena.Por ejemplo, en caso de que necesite cambiar cadenas con espacios en blanco o caracteres no permitidos en identificadores C/C++, puede convertir/eliminar/reemplazar esos caracteres para que la cadena sea un identificador válido.

void TestCase::SwitchString(QString word)
{
    // get information about the enum named "Cases"
    QMetaObject MetaObject = this->staticMetaObject;
    QMetaEnum MetaEnum = MetaObject.enumerator(MetaObject.indexOfEnumerator("Cases"));

    switch (MetaEnum.keyToValue(word.toUpper().toLatin1()))
    // or simply switch (MetaEnum.keyToValue(word)) if no string modification is needed
    {
        case THE:  /* do something */ break;
        case AT:   /* do something */ break;
        case IN:   /* do something */ break;
        case THIS: /* do something */ break;
        default:   /* do something */ break;
    }
}

Luego simplemente use la clase para cambiar las cadenas.Por ejemplo:

TestCase test;
test.SwitchString("At");
test.SwitchString("the");
test.SwitchString("aBCdxx");

Si puede utilizar un compilador de C++ moderno, entonces podría calcular un valor hash en tiempo de compilación para sus cadenas.En esta respuesta hay un ejemplo de un bastante simple constexpr función hash.

Entonces una solución puede verse así:

// function from https://stackoverflow.com/a/2112111/1150303
// (or use some other constexpr hash functions from this thread)
unsigned constexpr const_hash(char const *input) {
    return *input ?
    static_cast<unsigned int>(*input) + 33 * const_hash(input + 1) :
    5381;
}

QString switchStr = "...";
switch(const_hash(switchStr.toStdString().c_str()))
{
case const_hash("Test"):
    qDebug() << "Test triggered";
    break;
case const_hash("asdf"):
    qDebug() << "asdf triggered";
    break;
default:
    qDebug() << "nothing found";
    break;
}

Todavía no es una solución perfecta.Puede haber colisiones de hash (por lo tanto, pruebe su programa cada vez que agregue/cambie case) y hay que tener cuidado en la conversión de QString a char* si quieres usar exótico o utf personajes, por ejemplo.

Para c++ 11 agregar CONFIG += c++11 a su proyecto, para Qt5.Qt4: QMAKE_CXXFLAGS += -std=c++11

La respuesta de @DomTomCat ya abordó esto, pero dado que la pregunta se refiere específicamente a Qt, hay una manera mejor.

Qt ya tiene una función hash para QStrings, pero desafortunadamente qHash de Qt4 no está calificado como constexpr.Afortunadamente, Qt es de código abierto, por lo que podemos copiar la funcionalidad qHash para QStrings en nuestra propia función hash constexpr y usarla.

Fuente qHash de Qt4

Lo modifiqué para que solo necesite un parámetro (las cadenas literales siempre terminan en nulo):

uint constexpr qConstHash(const char *string)
{
    uint h = 0;

    while (*string != 0)
    {
        h = (h << 4) + *string++;
        h ^= (h & 0xf0000000) >> 23;
        h &= 0x0fffffff;
    }
    return h;
}

Una vez que haya definido esto, puede usarlo en declaraciones de cambio como esta:

QString string;
// Populate the QString somehow.

switch (qHash(string))
{
    case qConstHash("a"):
        // Do something.
        break;
    case qConstHash("b"):
        // Do something else.
        break;
}

Dado que este método utiliza el mismo código que Qt usa para calcular hashes, tendrá la misma resistencia a la colisión de hash que QHash, lo cual generalmente es muy bueno.La desventaja es que esto requiere un compilador bastante reciente; dado que tiene declaraciones de no retorno en la función hash constexpr, requiere C++14.

Como se señaló anteriormente, esto no es un problema de Qt, las declaraciones de cambio solo pueden usar expresiones constantes, mire las clases de colección a QSet es una buena solución

void initStopQwords(QSet<QString>& stopSet)
{
    // Ideally you want to read these from a file
    stopSet << "the";
    stopSet << "at";
    ...

}

bool isStopWord(const QSet<QString>& stopSet, const QString& word)
{
    return stopSet.contains(word);
}

prueba esto:

// file qsswitch.h
#ifndef QSSWITCH_H
#define QSSWITCH_H

#define QSSWITCH(__switch_value__, __switch_cases__) do{\
    const QString& ___switch_value___(__switch_value__);\
    {__switch_cases__}\
    }while(0);\

#define QSCASE(__str__, __whattodo__)\
    if(___switch_value___ == __str__)\
    {\
    __whattodo__\
    break;\
    }\

#define QSDEFAULT(__whattodo__)\
    {__whattodo__}\

#endif // QSSWITCH_H

cómo utilizar:

#include "qsswitch.h"

QString sW1 = "widget1";
QString sW2 = "widget2";

class WidgetDerived1 : public QWidget
{...};

class WidgetDerived2 : public QWidget
{...};

QWidget* defaultWidget(QWidget* parent)
{
    return new QWidget(...);
}

QWidget* NewWidget(const QString &widgetName, QWidget *parent) const
{
    QSSWITCH(widgetName,
             QSCASE(sW1,
             {
                 return new WidgetDerived1(parent);
             })
             QSCASE(sW2,
             {
                 return new WidgetDerived2(parent);
             })
             QSDEFAULT(
             {
                 return defaultWidget(parent);
             })
             )
}

hay algo de magia macro simple.después de preprocesar esto:

QSSWITCH(widgetName,
         QSCASE(sW1,
         {
             return new WidgetDerived1(parent);
         })
         QSCASE(sW2,
         {
             return new WidgetDerived2(parent);
         })
         QSDEFAULT(
         {
             return defaultWidget(parent);
         })
         )

funcionará así:

// QSSWITCH
do{
        const QString& ___switch_value___(widgetName);
        // QSCASE 1
        if(___switch_value___ == sW1)
        {
            return new WidgetDerived1(parent);
            break;
        }

        // QSCASE 2
        if(___switch_value___ == sW2)
        {
            return new WidgetDerived2(parent);
            break;
        }

        // QSDEFAULT
        return defaultWidget(parent);
}while(0);
case "the":
    //^^^ case label must lead to a constant expression

no soy consciente de cuarto de galón, pero puedes intentarlo.puedes evitar switch y usar directamente == a modo de comparación, si QString no es diferente a lo normal std::string.

if( word == "the" )
{
   // ..
}
else if( word == "at" )
{
   // ..
}
// ....

Esto parece un poco más sensato en mi humilde opinión.

bool isStopWord( QString w ) {
    return (
        w == "the" ||
        w == "at" ||
        w == "in" ||
        w == "your" ||
        w == "near" ||
        w == "all" ||
        w == "this"
    );
}

Sugeriría usar if y break.Esto acercaría el cambio de caso en el cálculo.

QString a="one"
if (a.contains("one"))
{

   break;
}
if (a.contains("two"))
{

   break;
}

Esto no tiene nada que ver con Qt, como tampoco tiene nada que ver con el color de tus calcetines.

La sintaxis del cambio de C++ es la siguiente:

char c = getc();
switch( c ) {
case 'a':
    a();
    break;
case 'b':
    b();
    break;
default:
    neither();
}

Si eso no ayuda, indique en detalle el mensaje de error, posible junto con el color de sus calcetines.

Editar:para responder a tu respuesta, no puedes usar switch con tipos no integrales.En particular, no puedes usar tipos de clases.No objetos de tipo QString y no objetos de ningún otro tipo.Puedes usar un if-else if-else construir en su lugar, o puede usar polimorfismo en tiempo de ejecución o tiempo de compilación, o sobrecarga, o cualquiera de las alternativas a un switch.

mira esto me ayuda

int main(int, char **)
{
    static const uint red_hash = 30900;
    static const uint green_hash = 7244734;
    static const uint blue_hash = 431029;
  else  
    static const uint red_hash = 112785;  
    static const uint green_hash = 98619139;  
    static const uint blue_hash = 3027034;
  endif

    QTextStream in(stdin), out(stdout);
    out << "Enter color: " << flush;
    const QString color = in.readLine();
    out << "Hash=" << qHash(color) << endl;

    QString answer;
    switch (qHash(color)) {
    case red_hash:
        answer="Chose red";
        break;
    case green_hash:
        answer="Chose green";
        break;
    case blue_hash:
        answer="Chose blue";
        break;
    default:
        answer="Chose something else";
        break;
    }
    out << answer << endl;
}

Es idéntico a una declaración de cambio de C++.

switch(var){
  case(option1):
      doesStuff();
      break;
  case(option2):
     etc();
     break;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top