Вопрос

Я хочу использовать switch-case в своей программе, но компилятор выдает мне эту ошибку:

switch expression of type 'QString' is illegal

Как я могу использовать switch заявление с QString?

Мой код выглядит следующим образом:

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 ;
}
Это было полезно?

Решение

Как я могу использовать оператор switch с QString?

Ты не можешь.На языке C++ switch оператор может использоваться только с целочисленными или перечисляемыми типами.Вы можете формально поместить объект типа class в switch оператор, но это просто означает, что компилятор будет искать определяемое пользователем преобразование, чтобы преобразовать его в тип integral или enum.

Другие советы

Вы можете, создав QStringList перед итерацией, следующим образом:

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

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

Тогда:

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

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

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

  default:
    ...
    break;
}

В C ++ невозможно переключаться непосредственно на строки.Однако это возможно в Qt с использованием QMetaEnum как показано здесь: Q_ENUM и как включить строку

Чтобы сделать это, сначала объявить перечисление с помощью строки, которые будут использоваться в случаях переключения как имя перечислителя в объявлении вашего класса.Затем добавьте перечисление к метаданным с помощью Q_ENUMS для того, чтобы программа могла выполнить поиск позже.

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

Затем в .cpp файл реализует необходимый переключатель после преобразования строки в соответствующее значение с помощью .

Сравнение чувствительно к регистру, поэтому, если вы хотите выполнить поиск без учета регистра, сначала преобразуйте входную строку в верхний / нижний регистр.Вы также можете выполнить другие преобразования, необходимые для строки.Например, если вам нужно заменить строки с пробелами или недопустимыми символами в идентификаторах C / C ++, вы можете преобразовать / удалить / заменить эти символы, чтобы сделать строку допустимым идентификатором.

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

Затем просто используйте класс для переключения строк.Например:

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

Если вы можете использовать современный компилятор C ++, то вы могли бы вычислить хэш-значение во время компиляции для ваших строк.В этот ответ вот пример довольно простого constexpr функция хеширования.

Таким образом, решение может выглядеть следующим образом:

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

Это все еще не идеальное решение.Могут возникнуть коллизии хэшей (следовательно, тестируйте свою программу всякий раз, когда вы добавляете / изменяете case) и вы должны быть осторожны при преобразовании из QString Для char* если вы хотите использовать экзотические или utf персонажи, например.

Для c ++ 11 добавьте CONFIG += c++11 к вашему проекту, для Qt5.Qt4: QMAKE_CXXFLAGS += -std=c++11

Ответ @DomTomCat уже касался этого, но поскольку вопрос конкретно касается Qt, есть лучший способ.

В Qt уже есть функция хэширования для QStrings, но, к сожалению, QHash Qt4 не квалифицируется как constexpr .К счастью, Qt имеет открытый исходный код, поэтому мы можем скопировать функциональность QHash для QStrings в нашу собственную функцию хеширования constexpr и использовать ее!

Источник QHash для Qt4

Я изменил его так, чтобы требовался только один параметр (строковые литералы всегда заканчиваются нулем).:

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

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

После того, как вы определили это, вы можете использовать это в операторах switch следующим образом:

QString string;
// Populate the QString somehow.

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

Поскольку этот метод использует тот же код, который Qt использует для вычисления хэшей, он будет обладать такой же устойчивостью к столкновению хэшей, что и QHash, что в целом очень хорошо.Недостатком является то, что для этого требуется довольно новый компилятор - поскольку в функции хеширования constexpr есть операторы невозврата, для этого требуется C ++ 14.

Как отмечалось ранее, это не проблема Qt, операторы switch могут использовать только постоянные выражения, посмотрите на классы коллекции a QSet это хорошее решение

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

попробуй это:

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

как использовать:

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

существует несколько простых макромагий.после предварительной обработки этого:

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

будет работать следующим образом:

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

Я не осведомлен о qt, но вы можете попробовать это сделать.Вы можете избежать switch и непосредственно использовать == для сравнения, если QString ничем не отличается от обычного std::string.

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

Это кажется немного более разумным, ИМХО.

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

Я бы предложил использовать if и break.Это сделало бы его близким к переключению регистра в вычислении.

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

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

   break;
}

Это не имеет никакого отношения к Qt, так же как и к цвету ваших носков.

Синтаксис коммутатора C ++ выглядит следующим образом:

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

Если это не поможет, пожалуйста, подробно перечислите сообщение об ошибке, возможно, вместе с цветом ваших носков.

Редактировать:чтобы ответить на ваш ответ, вы не можете использовать switch без каких-либо интегральных типов.В частности, вы не можете использовать типы классов.Не объекты типа QString и не объекты какого-либо другого типа.Вы можете использовать if-else if-else сконструировать вместо этого, или вы можете использовать полиморфизм во время выполнения или компиляции, или перегрузку, или любую из множества альтернатив switch.

Посмотри на это, это помогает мне

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

Он идентичен оператору C ++ switch.

switch(var){
  case(option1):
      doesStuff();
      break;
  case(option2):
     etc();
     break;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top