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

发布于 2024-10-26 18:57:28 字数 629 浏览 2 评论 0 原文

我想在程序中使用 switch-case,但编译器给出了此错误:

switch expression of type 'QString' is illegal

How can I use the switch statements with a 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 ;
}

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

switch expression of type 'QString' is illegal

How can I use the switch statement with a 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 ;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

心房敞 2024-11-02 18:57:28

您可以在迭代之前创建一个 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;
}

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

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;
}
反目相谮 2024-11-02 18:57:28

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

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

How can I use the switch statement with a QString?

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

一直在等你来 2024-11-02 18:57:28

@DomTomCat 的回答已经谈到了这一点,但由于问题是专门询问 Qt 的,所以有更好的方法。

Qt 已经有 QString 的散列函数,但不幸的是 Qt4 的 qHash 不符合 constexpr 资格。幸运的是,Qt 是开源的,因此我们可以将 QStrings 的 qHash 功能复制到我们自己的 constexpr 哈希函数中并使用它!

Qt4的qHash源

我已修改它只需要一个参数(字符串文字总是以 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;
}

一旦定义了它,您就可以在 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。

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

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!

Qt4's qHash source

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

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:

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.

断肠人 2024-11-02 18:57:28

在 C++ 中不可能直接切换字符串。然而在Qt中可以使用QMetaEnum 如下所示:Q_ENUM 以及如何开启一个字符串。您甚至不需要像 Anthony Hilyard 的答案中那样使用 C++14,并且匹配的情况不是字符串的哈希值,因此哈希冲突的可能性为零

基本上QMetaEnum可以从字符串转换为枚举值,反之亦然,因此我们将使用它跳转到正确的分支。一个小限制是字符串是枚举值,因此字符串必须是有效的 C++ 标识符。但这很容易解决,只需在必要时用特定规则替换特殊字符即可。

为此,首先声明一个枚举,并将在 switch case 中使用的字符串作为枚举器类声明中的名称。然后使用 Q_ENUMS 将枚举添加到元数据中,以便程序稍后进行搜索。

#include <QMetaEnum>

class TestCase : public QObject
{
    Q_OBJECT
    Q_ENUMS(Cases)        // metadata declaration

    QMetaObject MetaObject;
    QMetaEnum MetaEnum;   // enum metadata

    TestCase() :
    // get information about the enum named "Cases"
    MetaObject(this->staticMetaObject),
    MetaEnum(MetaObject.enumerator(MetaObject.indexOfEnumerator("Cases"))
    {}

public:
    explicit Test(QObject *parent = 0);

    enum Cases
    {
        THE, AT, IN, THIS // ... ==> strings to search, case sensitive
    };

public slots:
    void SwitchString(const QString &word);
};

然后使用 SwitchString 中实现所需的开关="nofollow noreferrer">QMetaEnum::keyToValue

比较区分大小写,因此如果您想要不区分大小写的搜索,请先将输入字符串转换为大写/小写。您还可以对字符串进行其他必要的转换。例如,如果您需要在 C++ 标识符中切换带有空格或禁止字符的字符串,您可以转换/删除/替换这些字符以使字符串成为有效的标识符。

void TestCase::SwitchString(const QString &word)
{
    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");

It's not possible to switch directly on strings in C++. However it's possible in Qt using QMetaEnum as shown here: Q_ENUM and how to switch on a string. You don't even need C++14 like in Anthony Hilyard's answer, and the matching cases are not the hashes of the strings so there's zero chance of hash collision

Basically QMetaEnum can convert from string to enum value and vice versa so we'll use that to jump to the correct branch. One small limitation is that strings are enum values so the string must be a valid C++ identifier. But that's easy to workaround, just replace the special characters with a specific rule if necessary

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

#include <QMetaEnum>

class TestCase : public QObject
{
    Q_OBJECT
    Q_ENUMS(Cases)        // metadata declaration

    QMetaObject MetaObject;
    QMetaEnum MetaEnum;   // enum metadata

    TestCase() :
    // get information about the enum named "Cases"
    MetaObject(this->staticMetaObject),
    MetaEnum(MetaObject.enumerator(MetaObject.indexOfEnumerator("Cases"))
    {}

public:
    explicit Test(QObject *parent = 0);

    enum Cases
    {
        THE, AT, IN, THIS // ... ==> strings to search, case sensitive
    };

public slots:
    void SwitchString(const QString &word);
};

Then just implement the needed switch inside SwitchString after converting the string to the corresponding value with QMetaEnum::keyToValue.

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 necessary to the string. For example in case you need to switch strings with blank spaces or forbidden characters in C++ identifiers, you may convert/remove/replace those characters to make the string a valid identifier.

void TestCase::SwitchString(const QString &word)
{
    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");
蓝眼睛不忧郁 2024-11-02 18:57:28

如果您可以使用现代 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 时都要测试您的程序),并且在从 QStringchar*utf 字符。

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

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

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 QString to char* if you want to use exotic or utf characters, for instance.

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

悍妇囚夫 2024-11-02 18:57:28

如前所述这不是 Qt 问题,switch 语句只能使用常量表达式,看看集合类 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);
}

As previously noted this is not a Qt problem, switch statements can only use constant expressions, look at the collection classes a QSet is a good 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);
}
软糯酥胸 2024-11-02 18:57:28

试试这个:

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

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);
淑女气质 2024-11-02 18:57:28
case "the":
    //^^^ case label must lead to a constant expression

我不知道qt,但你可以尝试一下。如果QString与正常的std::string没有什么不同,您可以避免switch并直接使用==进行比较代码>.

if( word == "the" )
{
   // ..
}
else if( word == "at" )
{
   // ..
}
// ....
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 switch and directly use == for comparison, if QString is no different than a normal std::string.

if( word == "the" )
{
   // ..
}
else if( word == "at" )
{
   // ..
}
// ....
倥絔 2024-11-02 18:57:28

恕我直言,这似乎更理智一些。

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

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"
    );
}
放我走吧 2024-11-02 18:57:28

我建议使用if和break。这将使其在计算中接近切换情况。

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

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

   break;
}

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

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

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

   break;
}
若言繁花未落 2024-11-02 18:57:28

晚会了,这是我前一段时间提出的一个解决方案,它完全遵守所要求的语法并适用于 c++11 及以上版本。

#include <uberswitch/uberswitch.hpp>

bool isStopWord( QString word )
{
bool flag = false ;

uswitch( word )
{
ucase ("the"):
    flag = true ;
    break ;
ucase ("at") :
    flag = true ;
    break ;
ucase ("in") :
    flag = true ;
    break ;
ucase ("your"):
    flag = true ;
    break ;
ucase ("near"):
    flag = true ;
    break ;
ucase ("all"):
    flag = true ;
    break ;
ucase ("this"):
    flag = true ;
    break ;
}

return flag ;
}

唯一需要注意的区别是使用 switch 代替 switchucase 代替 case, ucase 值周围的括号(必需的,因为这是一个宏)。

代码如下: https://github.com/falemagn/uberswitch

Late to the party, here's a solution I came up with some time ago, which completely abides to the requested syntax and works with c++11 onwards.

#include <uberswitch/uberswitch.hpp>

bool isStopWord( QString word )
{
bool flag = false ;

uswitch( word )
{
ucase ("the"):
    flag = true ;
    break ;
ucase ("at") :
    flag = true ;
    break ;
ucase ("in") :
    flag = true ;
    break ;
ucase ("your"):
    flag = true ;
    break ;
ucase ("near"):
    flag = true ;
    break ;
ucase ("all"):
    flag = true ;
    break ;
ucase ("this"):
    flag = true ;
    break ;
}

return flag ;
}

The only differences to be noticed are the usage of switch in place of switch and ucase instead of case, with the parenthesis around the ucase value (needed, baucause that's a macro).

Here's the code: https://github.com/falemagn/uberswitch

凉宸 2024-11-02 18:57:28

这与 Qt 无关,就像与你袜子的颜色无关一样。

C++ switch 语法如下:

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

如果这没有帮助,请详细列出错误消息,可能还有您袜子的颜色。

编辑:要回复您的回复,您不能将 switch 与非整数类型一起使用。特别是,您不能使用类类型。不是 QString 类型的对象,也不是任何其他类型的对象。您可以改用 if-else if-else 构造,也可以使用运行时或编译时多态性、重载或任何 switch 的替代方案。

This has nothing to do with Qt, just as it has nothing to do with the colour of your socks.

C++ switch syntax is as follows:

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

If that doesn't help then please list in detail the error message, possible along with the colour of you socks.

Edit: to respond to your reply, you can't use switch with none-integral types. In particular, you can't use class types. Not objects of type QString and not objects of any other type. You can use an if-else if-else construct instead, or you can use runtime or compile time polymorphism, or overloading, or any of the array of alternatives to a switch.

或十年 2024-11-02 18:57:28

看看这个,它对我有帮助

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

Check out this, it helps me

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;
}
绝影如岚 2024-11-02 18:57:28

它与 C++ switch 语句相同。

switch(var){
  case(option1):
      doesStuff();
      break;
  case(option2):
     etc();
     break;
}

It is identical to a C++ switch statement.

switch(var){
  case(option1):
      doesStuff();
      break;
  case(option2):
     etc();
     break;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文