оператор switch / case в C ++ с типом QString
-
12-11-2019 - |
Вопрос
Я хочу использовать 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 и использовать ее!
Я изменил его так, чтобы требовался только один параметр (строковые литералы всегда заканчиваются нулем).:
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;
}