Wie wähle ich einen Wertebereich in einer switch-statement aus?

Wenn ich versuche zu kompilieren, bekomme ich diesen Fehler:

 1> ------ Build gestartet: Projekt: Schlange, Konfiguration: Debug Win32 ------
 1> Übung.cpp
 1> c: \ Benutzer \ Robin \ Dokumente \ Visual Studio 2010 \ Projekte \ Schlange \ Schlange \ Übung.cpp (13): Fehler C2059: Syntaxerrors: '> ='
 1> c: \ Benutzer \ Robin \ Dokumente \ Visual Studio 2010 \ Projekte \ Schlange \ Schlange \ Übung.cpp (16): Fehler C2059: Syntaxerrors: '> ='
 1> c: \ Benutzer \ Robin \ Dokumente \ Visual Studio 2010 \ Projekte \ Schlange \ Schlange \ Übung.cpp (19): Fehler C2059: Syntaxerrors: '> ='
 1> c: \ Benutzer \ Robin \ Dokumente \ Visual Studio 2010 \ Projekte \ Schlange \ Schlange \ Übung.cpp (22): Fehler C2059: Syntaxerrors: '> ='
 1> c: \ Benutzer \ Robin \ Dokumente \ Visual Studio 2010 \ Projekte \ Schlange \ Schlange \ Übung.cpp (25): Fehler C2059: Syntaxerrors: '>'
 1> c: \ Benutzer \ Robin \ Dokumente \ Visual Studio 2010 \ Projekte \ Schlange \ Schlange \ Übung.cpp (28): Fehler C2059: Syntaxerrors: '=='
 1> c: \ Benutzer \ Robin \ Dokumente \ Visual Studio 2010 \ Projekte \ Schlange \ Schlange \ Übung.cpp (34): Warnung C4065: switch-statement enthält 'Standard', aber keine 'Fall' Etiketten
 ========== Build: 0 erfolgreich, 1 fehlgeschlagen, 0 aktuell, 0 übersprungen ==========

Code:

#include  using namespace std; int main(){ int score; //Vraag de score cout <> score; //Switch switch(score){ case >= 100: cout <= 50: cout <= 25: cout <= 10: cout < 0: cout << "e"; break; case == 0: cout << "f"; break; default: cout << "BAD VALUE"; break; } cout << endl; return 0; } 

Wie kann ich dieses Problem beheben? Es ist eine Konsolenanwendung, Win32 und meine IDE ist Windows Enterprise C ++ 2010.

Ich lerne von Anfang C ++ durch Game-Programmierung .

   

In C ++ sind Case-Labels konstante Ausdrücke, im Allgemeinen keine Ausdrücke. Sie benötigen eine Kette von if-then-else-statementen, um das zu tun, was Sie zu tun versuchen.

Alternativ können Sie die Werte im Switch aufzählen. Dies läuft marginal schneller (obwohl es in Fällen wie Ihnen nicht wichtig ist), aber es ist wesentlich weniger lesbar:

 switch(score) { case 0: cout < < "f"; break; case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: cout << "e"; break; case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: cout << "c"; break; // ...and so on, you get the idea... } 

Einige Compiler unterstützen Fallbereiche wie case x ... y als Erweiterung der C ++ – Sprache.

Beispiel:

 #include  using namespace std; int main(){ int score; //Vraag de score cout < < "Score:"; cin >> score; //Switch switch(score){ case 0: cout < < "a"; break; case 0 ... 9: cout << "b"; break; case 11 ... 24: cout << "c"; break; case 25 ... 49: cout << "d"; break; case 50 ... 100: cout << "e"; break; default: cout << "BAD VALUE"; break; } cout << endl; return 0; } 

GCC 4.9 , Clang 3.5.1 und der Intel C / C ++ - Compiler 13.0.1 scheinen dies zu unterstützen (versucht auf http://gcc.godbolt.org/ ). Auf der anderen Seite, Visual C ++ 19 nicht (versucht auf http://webcompiler.cloudapp.net/ ).

Sie können dieses Problem beheben, indem Sie eine Reihe von if / else if statementen verwenden. Switch / Case kann in C ++ nicht so verwendet werden.

Es kann mit einer std::map mit switch :

 enum Interval { One, Two, Three, NotFound }; // [0,10[ is One, [10,30[ is Two, [30,55[ is Three std::map imap { { { 0, One }, { 10, Two }, { 30, Three }, { 55, NotFound } }; Interval ivalue = NotFound; auto f = imap.lower_bound( value ); if( f != imap.end() ) ivalue = f->second; switch( ivalue ) { case One : ... case Two : ... case Three : ... default: ... } 

Es gibt eine GCC-Erweiterung , die genau das tut, was Sie wollen.

In C ++ kann eine switch-statement nur konstanten Integer-Werten entsprechen:

 switch (i) { case 1: //... stuff break; case 2: //... stuff break; default: //... stuff } 

Der Standard erlaubt dies nicht:

6.4.2 Die switch-statement [stmt.switch]

[…] Jede statement innerhalb der switch-statement kann wie folgt mit einem oder mehreren Case-Labels versehen werden:

case constant-expression :

wo der konstante Ausdruck ein ganzzahliger konstanter Ausdruck sein soll (5.19).

Mit anderen Worten, Sie können nur Fallwerte verwenden, die sich zu einer einzigen, ganzzahligen “harten” Kompilierzeitkonstante erweitern (zB case 5+6: enum {X = 3}; ... case X*X: .

Der Weg dahin ist, if statementen zu verwenden. ZB um zu ersetzen

 switch (x) case 0..100: 

du würdest stattdessen

 if (x>=0 && x< =100) 

.

std::map::upper_bound + C ++ 11 Lambdas

https://stackoverflow.com/a/35460297/895245 erwähnt lower_bound , aber wir können auch die enum dort mit Lambdas (oder inheritance, wenn Sie es nicht haben) loswerden.

 #include  #include  #include  int main() { std::string ret; const std::map> m{ {0, [&](){ ret = "too small"; }}, {2, [&](){ ret = "[0,2)"; }}, {5, [&](){ ret = "[2,5)"; }}, {7, [&](){ ret = "[5,7)"; }}, }; const auto end = m.end(); for (auto i = -1; i < 8; ++i) { auto it = m.upper_bound(i); if (it == end) { ret = "too large"; } else { it->second(); } std::cout < < i << " " << ret << std::endl; } } 

Ausgabe:

 -1 too small 0 [0,2) 1 [0,2) 2 [2,5) 3 [2,5) 4 [2,5) 5 [5,7) 6 [5,7) 7 too large 

Verwendung in Methoden mit static

Um dieses Muster effizient in classn zu verwenden, initialisieren Sie die Lambda-Map statisch, oder Sie zahlen jedes Mal n log(n) , um es von Grund auf neu zu erstellen.

Hier können wir mit der Initialisierung von {} einer static Methodenvariable davonkommen: Statische Variablen in classnmethoden , aber wir könnten auch die Methoden verwenden, die unter: static constructors in C ++? Ich muss private statische Objekte initialisieren

Es war notwendig, das Lambda-Kontext-Capture [&] in ein Argument umzuwandeln, oder das wäre undefiniert gewesen: const static auto lambda, das bei der Erfassung durch Referenz verwendet wurde

Beispiel, das dieselbe Ausgabe wie oben erzeugt:

 #include  #include  #include  #include  class RangeSwitch { public: void method(int x, std::string &ret) { static const std::map> m{ {0, [](std::string &ret){ ret = "too small"; }}, {2, [](std::string &ret){ ret = "[0,2)"; }}, {5, [](std::string &ret){ ret = "[2,5)"; }}, {7, [](std::string &ret){ ret = "[5,7)"; }}, }; static const auto end = m.end(); auto it = m.upper_bound(x); if (it == end) { ret = "too large"; } else { it->second(ret); } } }; int main() { RangeSwitch rangeSwitch; std::string ret; for (auto i = -1; i < 8; ++i) { rangeSwitch.method(i, ret); std::cout << i << " " << ret << std::endl; } } 

So funktioniert Switch nicht. Es braucht nur einzelne Werte. Sie müssen if-elseif-Blöcke verwenden

Ich hatte das gleiche Problem mit einem Punkte basierten Problem und während die “if / elseif” Aussagen waren gut zu verwenden, für Intervalle fand ich, dass die beste Option (für mich zumindest, weil ich mag, wie es aussieht und es ist einfacher für mich als Anfänger, um meine Fehler zu sehen) ist “1 … 10”. Aber vergessen Sie nicht, ein Leerzeichen zwischen der Zahl und den Punkten zu verwenden, oder das Programm denkt, dass Ihr Intervall eine Zahl ist, und Sie erhalten den Fehler “2 viele Dezimalpunkte …”. Ich hoffe es hilft.

 int score; int main() { cout< <"Enter score"<>score; switch(score){ case 100: cout< <"Your score is Perfect"< 

Switch-Case-statementen sind ein Ersatz für lange if-statementen, die eine Variable mit mehreren “ganzzahligen” Werten vergleichen (“ganzzahlige” Werte sind einfach Werte, die als Ganzzahl ausgedrückt werden können, z. B. der Wert eines Zeichens). Die Bedingung einer switch-statement ist ein Wert. Der Fall sagt, dass, wenn es den Wert von was auch immer nach diesem Fall hat, was auch immer folgt, der Doppelpunkt folgt. Die Pause wird verwendet, um aus den Case-statementen auszubrechen.

Daher können Sie solche bedingten statementen nicht für den Fall verwenden.

Die selektive Struktur: Schalter

Das hat bei mir funktioniert. Division der Marke durch 10 und dann Einstellung von Fall 10 und 9, um ein “A” anzuzeigen (dies zeigt ein “A” für irgendeinen Wert zwischen 90 und 100 an. Dann zeigt Fall 8 “B” an, dann zeigt Fall 7 ein ” C “für die Werte von 70-79 und so weiter.

 #include  using namespace std; main () { int mark; cout < < "enter your mark: "; cin >> mark; switch (mark/10) { case 10: case 9: cout < < "A"; break; case 8: cout << "B"; break; case 7: cout << "C"; break; case 6: cout << "D"; break; case 5: cout << "PASS"; break; default: cout << "FAIL"; break; } } 

Sie können Folgendes tun:

 //summarize the range to one value If score < 0 score = -1 switch(score){ case 1: //... break; case 2: //... break; case -1: //complete neg. range //... break; //... 

}

Hier ist ein Weg, von dem ich hoffe, dass er ausdrucksvoll und einfach zu folgen ist.

Sie werden vielleicht überrascht sein, wie weit gcc / clang usw. den erzeugten Code optimieren kann. Ich würde erwarten, dass es mindestens so effizient ist wie ein Switch / Case.

 #include  template struct switcher { constexpr switcher(Value const& value) : value_(value) {} constexpr switcher(Value const& value, bool enabled) : value_(value), enabled(enabled) {} template constexpr auto in_range(From&& from, To&& to, F&& f) { if (enabled and (from < = value_ and value_ <= to)) { f(); return switcher(value_, false); } else { return *this; } }; template constexpr auto otherwise(F&& f) { if (enabled) f(); } Value const& value_; const bool enabled = true; }; template constexpr auto decision(Value const& value) { return switcher(value); } void test(int x) { decision(x) .in_range(0, 10, [&] { std::cout < < x << " maps to option A\n"; }) .in_range(11, 20, [&] { std::cout << x << " maps to option B\n"; }) .otherwise([&] { std::cout << x << " is not covered\n"; }); } int main(int argc, char **argv) { test(5); test(14); test(22); } 

Eine möglicherweise nützliche Erkenntnis ist, dass switch einen Ausdruck akzeptiert, so dass Sie mehrere Eingabewerte auf einen Switch-Fall reduzieren können. Es ist ein großes hässliches, aber zur Überlegung:

 switch (score / 10) { case 10: cout < < "a"; break; case 9: case 8: case 7: case 6: case 5: cout << "b"; break; case 4: case 3: cout << "c"; break; case 2: if (score >= 25) { cout < < "c"; break; } // else fall through... case 1: cout << "d"; break; case 0: cout << (score > 0 ? "e" : "f"); break; default: cout < < "BAD VALUE"; break; } 

Natürlich könnten Sie durch 5 geteilt haben und case 4: (für 20-24) vs case 5: (25-29) anstatt ein if im case 2: :, aber /10 ist wohl intuitiver.

Ich weiß, das ist eine alte Frage, aber da switch statementen tatsächlich Wrapper um Labels sind, finde ich, dass goto hier (gut) verwendet werden kann.

  int value = 40; if (value < 10) { std::cout << "value < 10" << std::endl; goto end; } if (value < 50) { std::cout << "value < 50" << std::endl; goto end; } if (value > 30) { std::cout < < "value > 30" < < std::endl; goto end; } end: // resume 

Auf diese Weise können Sie alle else s weglassen und es kompakt halten. Sie sollten vorsichtig sein, wenn Sie goto (im Allgemeinen) verwenden.

Etwas wie das?

 case 'A'..'Z' where a not in ['I','L','O']: 

Leider implementiert kein Compiler, den ich kenne, diese spezielle Erweiterung, obwohl GCC Bereiche hat, wie andere Antworten darauf hingewiesen haben. Für die Portabilität können Sie dieses DWTFYW-lizenzierte Snippet ausschneiden und einfügen. Wenn Sie eine benutzerdefinierte Enumeration verwenden, können Sie die Codegenerierung verwenden, um etwas Ähnliches zu erstellen.

 #define CASE_NUMBER \ case'0':case'1':case'2':case'3':case'4':\ case'5':case'6':case'7':case'8':case'9' #define CASE_ALPHA_LOWER \ case'a':case'b':case'c':case'd':\ case'e':case'f':case'g':case'h':\ case'i':case'j':case'k':case'l':\ case'm':case'n':case'o':case'p':\ case'q':case'r':case's':case't':\ case'u':case'v':case'w':case'x':\ case'y':case'z' #define CASE_ALPHA_UPPER \ case'A':case'B':case'C':case'D':\ case'E':case'F':case'G':case'H':\ case'I':case'J':case'K':case'L':\ case'M':case'N':case'O':case'P':\ case'Q':case'R':case'S':case'T':\ case'U':case'V':case'W':case'X':\ case'Y':case'Z' #define CASE_ALPHA CASE_ALPHA_UPPER:CASE_ALPHA_LOWER #define CASE_ALPHANUM CASE_ALPHA:CASE_NUMBER 

Wenn Sie auf GHCI wie die Online-Version unter https://ghc.io/ zugreifen, können Sie einfach das generieren, was Sie brauchen, und es in eine Kopfzeile einfügen, z

 foldl (++) "" ["case" ++ show x ++ ":" | x < - ['A'..'Z'], not $ x `elem` ['I','L','O']]