switch/case statement in C++ with a QString type
我想在程序中使用大小写转换,但是编译器给我这个错误:
1 | switch expression of type 'QString' is illegal |
如何将
我的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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 ; } |
How can I use the switch statement with a QString?
你不能在C ++语言中,
您可以在迭代之前创建一个QStringList,如下所示:
1 2 3 4 5 6 7 8 | QStringList myOptions; myOptions <<"goLogin" <<"goAway" <<"goRegister"; /* goLogin = 0 goAway = 1 goRegister = 2 */ |
然后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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中使用
为此,首先在类声明中声明一个枚举,其中包含要在切换案例中使用的字符串作为枚举器名称。然后使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #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); }; |
然后,在
比较是区分大小写的,因此,如果要进行不区分大小写的搜索,请首先将输入字符串转换为大写/小写。您还可以对字符串进行其他所需的转换。例如,如果您需要在C / C ++标识符中切换带有空格或不允许的字符的字符串,则可以转换/删除/替换这些字符以使字符串成为有效的标识符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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; } } |
然后只需使用该类来切换字符串。例如:
1 2 3 4 | TestCase test; test.SwitchString("At"); test.SwitchString("the"); test.SwitchString("aBCdxx"); |
@DomTomCat的答案已经涉及到此问题,但是由于该问题专门询问Qt,因此有更好的方法。
Qt已经具有用于QStrings的哈希函数,但是不幸的是Qt4的qHash没有资格作为constexpr。幸运的是,Qt是开源的,因此我们可以将QStrings的qHash功能复制到我们自己的constexpr哈希函数中并使用它!
Qt4的qHash源
我将其修改为仅需要一个参数(字符串文字始终以null终止):
1 2 3 4 5 6 7 8 9 10 11 12 | 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语句中使用它,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 | 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。
如果可以使用现代C ++编译器,则可以为字符串计算编译时哈希值。在此答案中,有一个非常简单的
因此,解决方案如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // 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; } |
它仍然不是一个完美的解决方案。可能存在哈希冲突(因此,每次添加/更改
对于c ++ 11,对于Qt5,将
尝试这个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // 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 |
如何使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #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); }) ) } |
有一些简单的宏魔术。预处理后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | QSSWITCH(widgetName, QSCASE(sW1, { return new WidgetDerived1(parent); }) QSCASE(sW2, { return new WidgetDerived2(parent); }) QSDEFAULT( { return defaultWidget(parent); }) ) |
将像这样工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // 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); |
如前所述,这不是Qt问题,switch语句只能使用常量表达式,查看集合类
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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); } |
我建议使用if和break。这将使得在计算中接近切换大小写。
1 2 3 4 5 6 7 8 9 10 11 | QString a="one" if (a.contains("one")) { break; } if (a.contains("two")) { break; } |
恕我直言,这似乎有些理智。
1 2 3 4 5 6 7 8 9 10 11 | bool isStopWord( QString w ) { return ( w =="the" || w =="at" || w =="in" || w =="your" || w =="near" || w =="all" || w =="this" ); } |
1 2 | case"the": //^^^ case label must lead to a constant expression |
我不知道qt,但是您可以尝试一下。如果
1 2 3 4 5 6 7 8 9 | if( word =="the" ) { // .. } else if( word =="at" ) { // .. } // .... |
看看这个,对我有帮助
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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; } |
这与Qt无关,就像它与袜子的颜色无关。
C ++开关语法如下:
1 2 3 4 5 6 7 8 9 10 11 | char c = getc(); switch( c ) { case 'a': a(); break; case 'b': b(); break; default: neither(); } |
如果那没有帮助,请详细列出错误消息,以及袜子的颜色。
编辑:要回复您的答复,您不能将
它与C ++ switch语句相同。
1 2 3 4 5 6 7 8 | switch(var){ case(option1): doesStuff(); break; case(option2): etc(); break; } |