switch / case-Anweisung in C ++ mit einem QString-Typ
-
12-11-2019 - |
Frage
Ich möchte switch-case in meinem Programm verwenden, aber der Compiler gibt mir diesen Fehler:
switch expression of type 'QString' is illegal
Wie kann ich das verwenden switch
aussage mit einem QString
?
Mein Code lautet wie folgt:
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 ;
}
Lösung
Wie kann ich die switch-Anweisung mit einem QString verwenden?
Das kannst du nicht.In C ++ - Sprache switch
anweisung kann nur mit Integral- oder Enum-Typen verwendet werden.Sie können ein Objekt vom Klassentyp formal in a einfügen switch
anweisung, aber das bedeutet einfach, dass der Compiler nach einer benutzerdefinierten Konvertierung sucht, um sie in einen Integral- oder Enum-Typ zu konvertieren.
Andere Tipps
Sie können eine QStringList vor der Iteration wie folgt erstellen:
QStringList myOptions;
myOptions << "goLogin" << "goAway" << "goRegister";
/*
goLogin = 0
goAway = 1
goRegister = 2
*/
Dann:
switch(myOptions.indexOf("goRegister")){
case 0:
// go to login...
break;
case 1:
// go away...
break;
case 2:
//Go to Register...
break;
default:
...
break;
}
Es ist nicht möglich, Strings in C ++ direkt einzuschalten.Es ist jedoch in Qt möglich mit QMetaEnum
wie hier gezeigt: Q_ENUM
und wie man eine Saite anschaltet
Um das zu tun, zuerst deklarieren Sie eine Aufzählung mit dem strings, die in Schaltergehäusen verwendet werden sollen als Enumeratorname in Ihrer Klassendeklaration.Fügen Sie dann die Aufzählung zu den Metadaten hinzu mit Q_ENUMS
damit das Programm später suchen kann.
#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);
};
Dann in der .cpp
datei implementiert den benötigten Schalter, nachdem die Zeichenfolge mit in den entsprechenden Wert konvertiert wurde .
Wenn Sie also eine Suche ohne Berücksichtigung der Groß- und Kleinschreibung wünschen, konvertieren Sie die Eingabezeichenfolge zuerst in Groß- / Kleinschreibung.Sie können auch andere Transformationen an der Zeichenfolge vornehmen.Wenn Sie beispielsweise Zeichenfolgen mit Leerzeichen oder nicht zulässigen Zeichen in C / C ++ - Bezeichnern wechseln müssen, können Sie diese Zeichen konvertieren / entfernen / ersetzen, um die Zeichenfolge zu einem gültigen Bezeichner zu machen.
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;
}
}
Verwenden Sie dann einfach die Klasse zum Wechseln der Zeichenfolgen.Beispielsweise:
TestCase test;
test.SwitchString("At");
test.SwitchString("the");
test.SwitchString("aBCdxx");
Wenn Sie einen modernen C ++ - Compiler verwenden können, können Sie einen Kompilierungszeit-Hashwert für Ihre Zeichenfolgen berechnen.In diese Antwort es gibt ein Beispiel für eine ziemlich einfache constexpr
Hashfunktion.
Eine Lösung kann also so aussehen:
// 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;
}
Es ist immer noch keine perfekte Lösung.Es kann zu Hash-Kollisionen kommen (testen Sie daher Ihr Programm bei jedem Hinzufügen / Ändern case
) und Sie müssen bei der Konvertierung von vorsichtig sein QString
zu char*
wenn Sie exotische oder verwenden möchten utf
charaktere zum Beispiel.
Für c ++ 11 hinzufügen CONFIG += c++11
zu Ihrem Projekt, für Qt5.Qt4: QMAKE_CXXFLAGS += -std=c++11
@ domtomcats Antwort hat dies bereits angesprochen, aber da die Frage speziell nach Qt fragt, gibt es einen besseren Weg.
Qt hat bereits eine Hashing-Funktion für QStrings, aber leider ist QHash von Qt4 nicht als constexpr qualifiziert.Glücklicherweise ist Qt Open Source, sodass wir die QHash-Funktionalität für QStrings in unsere eigene constexpr-Hashing-Funktion kopieren und diese verwenden können!
Ich habe es so geändert, dass nur ein Parameter benötigt wird (Zeichenfolgenliterale sind immer nullterminiert):
uint constexpr qConstHash(const char *string)
{
uint h = 0;
while (*string != 0)
{
h = (h << 4) + *string++;
h ^= (h & 0xf0000000) >> 23;
h &= 0x0fffffff;
}
return h;
}
Sobald Sie dies definiert haben, können Sie es in switch-Anweisungen wie folgt verwenden:
QString string;
// Populate the QString somehow.
switch (qHash(string))
{
case qConstHash("a"):
// Do something.
break;
case qConstHash("b"):
// Do something else.
break;
}
Da diese Methode denselben Code verwendet, den Qt zur Berechnung von Hashes verwendet, weist sie die gleiche Hash-Kollisionsresistenz wie QHash auf, was im Allgemeinen sehr gut ist.Der Nachteil ist, dass dies einen relativ neuen Compiler erfordert - da er Nicht-Rückgabe-Anweisungen in der Hashing-Funktion constexpr enthält, ist C ++ 14 erforderlich.
Wie bereits erwähnt, ist dies kein Qt-Problem, switch-Anweisungen können nur konstante Ausdrücke verwenden, schauen Sie sich die Sammlungsklassen a an QSet
ist eine gute Lösung
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);
}
versuchen Sie dies:
// 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
wie zu verwenden:
#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);
})
)
}
es gibt einige einfache Makro-Magie.nach der Vorverarbeitung dieses:
QSSWITCH(widgetName,
QSCASE(sW1,
{
return new WidgetDerived1(parent);
})
QSCASE(sW2,
{
return new WidgetDerived2(parent);
})
QSDEFAULT(
{
return defaultWidget(parent);
})
)
wird so funktionieren:
// 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);
case "the":
//^^^ case label must lead to a constant expression
Mir ist nichts bekannt qt, aber du kannst es versuchen.Sie können vermeiden switch
und direkt verwenden ==
zum Vergleich, wenn QString
ist nicht anders als ein normaler std::string
.
if( word == "the" )
{
// ..
}
else if( word == "at" )
{
// ..
}
// ....
Das scheint IMHO etwas vernünftiger zu sein.
bool isStopWord( QString w ) {
return (
w == "the" ||
w == "at" ||
w == "in" ||
w == "your" ||
w == "near" ||
w == "all" ||
w == "this"
);
}
Ich würde vorschlagen, if und break zu verwenden.Dies würde es in der Berechnung nahe an den Wechselfall bringen.
QString a="one"
if (a.contains("one"))
{
break;
}
if (a.contains("two"))
{
break;
}
Das hat nichts mit Qt zu tun, genauso wenig wie es mit der Farbe Ihrer Socken zu tun hat.
Die C ++ - Switch-Syntax lautet wie folgt:
char c = getc();
switch( c ) {
case 'a':
a();
break;
case 'b':
b();
break;
default:
neither();
}
Wenn das nicht hilft, listen Sie bitte die Fehlermeldung detailliert auf, möglicherweise zusammen mit der Farbe Ihrer Socken.
Bearbeiten:um auf Ihre Antwort zu antworten, können Sie nicht verwenden switch
mit nicht ganzzahligen Typen.Insbesondere können Sie keine Klassentypen verwenden.Keine Objekte vom Typ QString
und keine Objekte irgendeines anderen Typs.Sie können eine verwenden if-else if-else
konstruieren Sie stattdessen, oder Sie können Laufzeit- oder Kompilierzeitpolymorphismus oder Überladung oder eine beliebige der Alternativen zu a verwenden switch
.
Schau dir das an, es hilft mir
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;
}
Es ist identisch mit einer C ++ - switch-Anweisung.
switch(var){
case(option1):
doesStuff();
break;
case(option2):
etc();
break;
}