web-dev-qa-db-ja.com

QString型のC ++のswitch / caseステートメント

プログラムでswitch-caseを使用したいのですが、コンパイラから次のエラーが表示されます。

switch expression of type 'QString' is illegal

switchQStringステートメントを使用するにはどうすればよいですか?

私のコードは次のとおりです。

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

QStringでswitchステートメントを使用するにはどうすればよいですか?

できません。 C++言語では、switchステートメントは整数型または列挙型でのみ使用できます。クラス型のオブジェクトを正式にswitchステートメントに入れることができますが、それは単にコンパイラがユーザー定義の変換を探して整数型または列挙型に変換することを意味します。

29
AnT

次のように、反復の前に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;
}
25
Lauro Oliveira

C++で文字列を直接切り替えることはできません。ただし、Qtでは、次のように QMetaEnum を使用できます。 Q_ENUMと文字列を切り替える方法

そのためには、最初にenumを宣言を、スイッチ宣言で使用する文字列をクラス宣言の列挙子名として使用します。次に、Q_ENUMSを使用して、enumをメタデータに追加して、プログラムが後で検索できるようにします。

#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");
4
phuclv

最新の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文字を使用する場合は、utfからchar*への変換に注意する必要があります。

C++ 11の場合、Qt5の場合はCONFIG += c++11をプロジェクトに追加します。 Qt4:QMAKE_CXXFLAGS += -std=c++11

3
DomTomCat

@DomTomCatの答えはすでにこれに触れていますが、質問はQtについて具体的に尋ねているため、より良い方法があります。

QtにはすでにQStringのハッシュ関数がありますが、残念ながらQt4のqHashはconstexprとして修飾されていません。幸い、Qtはオープンソースなので、QStringsのqHash機能を独自のconstexprハッシュ関数にコピーして使用できます。

Qt4のqHashソース

パラメーターを1つだけ必要とするように変更しました(文字列リテラルは常に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ハッシュ関数にnon-returnステートメントがあるため、C++ 14が必要です。

3
Anthony Hilyard

これを試して:

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

前述のように、これは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);
}
1

Ifとbreakを使用することをお勧めします。これにより、計算でケースを切り替えるのに近くなります。

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

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

   break;
}
0
case "the":
    //^^^ case label must lead to a constant expression

qtについては知りませんが、試してみてください。 switchが通常の==と変わらない場合は、QStringを避け、比較のためにstd::stringを直接使用できます。

if( Word == "the" )
{
   // ..
}
else if( Word == "at" )
{
   // ..
}
// ....
0
Mahesh

これは、私見では少し気味が悪いようです。

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