プログラムで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 ;
}
QStringでswitchステートメントを使用するにはどうすればよいですか?
できません。 C++言語では、switch
ステートメントは整数型または列挙型でのみ使用できます。クラス型のオブジェクトを正式にswitch
ステートメントに入れることができますが、それは単にコンパイラがユーザー定義の変換を探して整数型または列挙型に変換することを意味します。
次のように、反復の前に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
と文字列を切り替える方法
そのためには、最初に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");
最新の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
@DomTomCatの答えはすでにこれに触れていますが、質問はQtについて具体的に尋ねているため、より良い方法があります。
QtにはすでにQStringのハッシュ関数がありますが、残念ながらQt4のqHashはconstexprとして修飾されていません。幸い、Qtはオープンソースなので、QStringsのqHash機能を独自のconstexprハッシュ関数にコピーして使用できます。
パラメーターを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が必要です。
これを試して:
// 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);
前述のように、これは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);
}
Ifとbreakを使用することをお勧めします。これにより、計算でケースを切り替えるのに近くなります。
QString a="one"
if (a.contains("one"))
{
break;
}
if (a.contains("two"))
{
break;
}
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"
);
}