Question instruction switch / case en C ++ avec un type QString


Je veux utiliser switch-case dans mon programme mais le compilateur génère une erreur. Comment puis-je utiliser le switch déclaration avec un QString?

Le compilateur me donne cette erreur:

switch expression of type 'QString' is illegal

Mon code est le suivant:

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 ;
}

21
2018-03-27 20:29


origine


Réponses:


Comment puis-je utiliser l'instruction switch avec une QString?

Vous ne pouvez pas. En langage C ++ switch statement ne peut être utilisé qu'avec les types intégrale ou enum. Vous pouvez formellement mettre un objet de type classe dans un switch statement, mais cela signifie simplement que le compilateur recherchera une conversion définie par l'utilisateur pour le convertir en type intégrale ou enum.


25
2018-03-27 20:45



Vous pouvez, en créant un QStringList avant l’itération, comme ceci:

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

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

Alors:

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

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

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

  default:
    ...
    break;
}

24
2017-07-01 02:35



Il n'est pas possible de basculer directement sur des chaînes en C ++. Cependant, il est possible d'utiliser Qt QMetaEnum comme indiqué ici: Q_ENUM et comment allumer une chaîne

Pour ce faire, d'abord déclarer un enum avec le chaînes à utiliser dans les boîtiers de commutation comme nom d'énumérateur dans votre déclaration de classe. Puis ajoutez l'énumération aux métadonnées avec Q_ENUMS afin que le programme puisse rechercher plus tard.

#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);
};

Alors dans le .cpp fichier implémente le commutateur nécessaire après la conversion de la chaîne à la valeur correspondante avec .

La comparaison est sensible à la casse, donc si vous souhaitez une recherche insensible à la casse, convertissez d'abord la chaîne d'entrée en majuscules / minuscules. Vous pouvez également effectuer d'autres transformations nécessaires à la chaîne. Par exemple, si vous devez changer de chaîne avec des espaces vides ou des caractères non autorisés dans les identifiants C / C ++, vous pouvez convertir / supprimer / remplacer ces caractères pour que la chaîne devienne un identifiant valide.

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;
    }
}

Ensuite, utilisez simplement la classe pour changer de chaîne. Par exemple:

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

3
2017-09-16 16:12



Comme indiqué précédemment, ce n'est pas un problème Qt, les instructions switch ne peuvent utiliser que des expressions constantes, regardez les classes de collection a QSet est une bonne solution

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);
}

1
2018-03-27 23:32



essaye ça:

// 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

comment utiliser:

#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);
             })
             )
}

il y a une simple macro-magie. après le prétraitement ceci:

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

fonctionnera comme ceci:

// 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);

1
2017-09-12 11:38



Si vous pouvez utiliser un compilateur C ++ moderne, vous pouvez calculer une valeur de hachage pour vos chaînes. Dans cette réponse il y a un exemple plutôt simple constexpr fonction de hachage.

Donc, une solution peut ressembler à ceci:

// 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;
}

Ce n'est toujours pas une solution parfaite. Il peut y avoir des collisions de hachage (donc testez votre programme chaque fois que vous ajoutez / modifiez case) et vous devez être prudent dans la conversion de QString à char* si vous voulez utiliser exotique ou utf des personnages, par exemple.

Pour c ++ 11 ajouter CONFIG += c++11 à votre projet, pour Qt5. Qt4: QMAKE_CXXFLAGS += -std=c++11


1
2018-03-05 11:21



case "the":
    //^^^ case label must lead to a constant expression

Je ne suis pas au courant de qt, mais vous pouvez essayer ceci. Vous pouvez éviter switch et directement utiliser == pour comparaison, si QString n'est pas différent d'une normale std::string.

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

0
2018-03-27 20:49



Cela semble un peu plus sain à mon humble avis.

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

0
2018-03-28 21:29



Regarde ça, ça m'aide

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;
}

0
2017-12-20 11:53