C++ 中带有 QString 类型的 switch/case 语句

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5452188/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 18:12:31  来源:igfitidea点击:

switch/case statement in C++ with a QString type

c++qtswitch-statementqt4qstring

提问by amiref

I want to use switch-case in my program but the compiler gives me this error:

我想在我的程序中使用 switch-case 但编译器给了我这个错误:

switch expression of type 'QString' is illegal

How can I use the switchstatement with a QString?

如何使用switch带有的语句QString

My code is as follows:

我的代码如下:

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

回答by AnT

How can I use the switch statement with a QString?

如何将 switch 语句与 QString 一起使用?

You can't. In C++ language switchstatement can only be used with integral or enum types. You can formally put an object of class type into a switchstatement, but that simply means that the compiler will look for a user-defined conversion to convert it to integral or enum type.

你不能。在 C++ 语言中,switch语句只能与整型或枚举类型一起使用。您可以将类类型的对象正式放入switch语句中,但这仅意味着编译器将查找用户定义的转换以将其转换为整型或枚举类型。

回答by Lauro Oliveira

You can, creating an QStringList before iteration, like this:

您可以在迭代之前创建一个 QStringList ,如下所示:

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

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

Then:

然后:

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

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

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

  default:
    ...
    break;
}

回答by phuclv

It's not possible to switch directly on strings in C++. However it's possible in Qt using QMetaEnumas shown here: Q_ENUMand how to switch on a string

在 C++ 中无法直接切换字符串。但是,在 Qt 中可以使用QMetaEnum如下所示:Q_ENUM以及如何打开字符串

To do that, first declare an enumwith the strings to be used in switch casesas enumerator name in your class declaration. Then add the enum to the metadata with Q_ENUMSin order for the program to search later.

为此,首先在类声明中声明一个枚举,其中包含要在 switch case 中使用字符串作为枚举器名称。然后将枚举添加到元数据中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);
};

Then in the .cppfile implement the needed switch after converting the string to the corresponding value with .

然后在.cpp文件中实现将字符串转换为相应值后所需的开关.

The comparison is case sensitive so if you want a case insensitive search, convert the input string to upper/lower case first. You can also do other transformations needed to the string. For example in case you need to switch strings with blank spaces or unallowed characters in C/C++ identifiers, you may convert/remove/replace those characters to make the string a valid identifier.

比较区分大小写,因此如果您想要不区分大小写的搜索,请先将输入字符串转换为大写/小写。您还可以对字符串进行其他所需的转换。例如,如果您需要在 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;
    }
}

Then just use the class for switching the strings. For example:

然后只需使用该类来切换字符串。例如:

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

回答by DomTomCat

If you can use a modern C++ compiler then you could compute a compile time hash value for your strings. In this answerthere's an example of a rather simple constexprhashing function.

如果您可以使用现代 C++ 编译器,那么您可以为您的字符串计算编译时哈希值。在这个答案中有一个相当简单的constexpr散列函数的例子。

So a solution can look like this:

因此,解决方案可能如下所示:

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

It is still not a perfect solution. There can be hash collisions (hence test your program whenever you add/change case) and you have to be careful in the conversion from QStringto char*if you want to use exotic or utfcharacters, for instance.

它仍然不是一个完美的解决方案。可能存在哈希冲突(因此,无论何时添加/更改case,都要测试您的程序),例如QStringchar*如果您想使用异国情调或utf字符,则必须小心从到的转换。

For c++ 11 add CONFIG += c++11to your project, for Qt5. Qt4: QMAKE_CXXFLAGS += -std=c++11

对于 C++ 11 添加CONFIG += c++11到您的项目中,对于 Qt5。Qt4:QMAKE_CXXFLAGS += -std=c++11

回答by Anthony Hilyard

@DomTomCat's answer already touched on this, but since the question is specifically asking about Qt, there is a better way.

@DomTomCat 的回答已经涉及到这一点,但由于这个问题专门询问 Qt,因此有更好的方法。

Qt already has a hashing function for QStrings, but unfortunately Qt4's qHash is not qualified as a constexpr. Luckily Qt is open source, so we can copy the qHash functionality for QStrings into our own constexpr hashing function and use that!

Qt 已经有 QStrings 的散列函数,但遗憾的是 Qt4 的 qHash 没有资格作为 constexpr。幸运的是 Qt 是开源的,所以我们可以将 QStrings 的 qHash 功能复制到我们自己的 constexpr 散列函数中并使用它!

Qt4's qHash source

Qt4的qHash源码

I've modified it to only need one parameter (string literals are always null-terminated):

我已经将它修改为只需要一个参数(字符串文字总是以 null 结尾):

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

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

Once you've defined this, you can use it in switch statements like so:

一旦你定义了它,你就可以在 switch 语句中使用它,如下所示:

QString string;
// Populate the QString somehow.

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

Since this method uses the same code Qt uses to calculate hashes, it will have the same hash collision resistance as QHash, which is generally very good. The downside is that this requires a fairly recent compiler--since it has non-return statements in the constexpr hashing function, it requires C++14.

由于这种方法使用了Qt用来计算hash的相同代码,所以它会具有和QHash一样的hash抗碰撞能力,一般来说是非常好的。缺点是这需要一个相当新的编译器——因为它在 constexpr 散列函数中有非返回语句,它需要 C++14。

回答by Harald Scheirich

As previously noted this is not a Qt problem, switch statements can only use constant expressions, look at the collection classes a QSetis a good solution

如前所述这不是Qt问题,switch语句只能使用常量表达式,看集合类aQSet是一个很好的解决方案

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

回答by moskk

try this:

尝试这个:

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

how to use:

如何使用:

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

there is some simple macro magic. after preprocessing this:

有一些简单的宏魔法。预处理后:

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

will work like this:

将像这样工作:

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

回答by weberc2

This seems a little saner IMHO.

恕我直言,这似乎有点理智。

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

回答by Mahesh

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

I am not aware of qt, but you can give this a try. You can avoid switchand directly use ==for comparison, if QStringis no different than a normal std::string.

我不知道qt,但你可以试试这个。您可以避免switch并直接==用于比较,如果QString与正常std::string.

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

回答by Drl Sherif Omran

I would suggest to use if and break. This would make it near to switch case in the computation.

我建议使用 if 和 break。这将使其接近于在计算中切换大小写。

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

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

   break;
}