关于c ++:如何在switch语句中选择一系列值?

How do I select a range of values in a switch statement?

当我试图编译时,我得到了这个错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1>------ Build started: Project: snake, Configuration: Debug Win32 ------
1>  exercise.cpp
1>c:\users
obin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(13): error C2059: syntax error : '>='
1>c:\users
obin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(16): error C2059: syntax error : '>='
1>c:\users
obin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(19): error C2059: syntax error : '>='
1>c:\users
obin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(22): error C2059: syntax error : '>='
1>c:\users
obin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(25): error C2059: syntax error : '>'
1>c:\users
obin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(28): error C2059: syntax error : '=='
1>c:\users
obin\documents\visual studio 2010\projects\snake\snake\exercise.cpp(34): warning C4065: switch statement contains 'default' but no 'case' labels
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
using namespace std;

int main(){
    int score;

    //Vraag de score
    cout <<"Score:";
    cin >> score;

    //Switch
    switch(score){
        case >= 100:
            cout <<"a";
            break;
        case >= 50:
            cout <<"b";
            break;
        case >= 25:
            cout <<"c";
            break;
        case >= 10:
            cout <<"d";
            break;
        case > 0:
            cout <<"e";
            break;
        case == 0:
            cout <<"f";
            break;
        default:
            cout <<"BAD VALUE";
            break;
    }
    cout << endl;
    return 0;
}

我如何解决这个问题?它是控制台应用程序,Win32和我的IDE是Windows企业C++ 2010。

我从C++开始,通过游戏编程学习。


一些编译器支持ECDOX1(5)作为CA++语言的扩展。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
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、CLAN 3.5.1和英特尔C/C++编译器130.1似乎支持它(尝试在http://gcc.Gooth.org/)上。另一方面,VisualC++ 19没有(在http://WebCalpul.CyrdApp.NET/)上试用。


在C++中,标签是常量表达式,而不是一般表达式。你需要一系列if-then-else语句来完成你想要做的。

或者,可以枚举开关中的值。它运行得稍微快一点(尽管在像您这样的情况下并不重要),但可读性要差得多:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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...

}


您可以使用一系列if/else if语句来解决这个问题。在C++中,开关/外壳不能像这样使用。


可以使用std::mapswitch来完成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
enum Interval {
   One,
   Two,
   Three,
   NotFound };

// [0,10[ is One, [10,30[ is Two, [30,55[ is Three
std::map<int,Interval> 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: ...
}


在C++中,开关语句只能匹配常数整数值:

1
2
3
4
5
6
7
8
9
10
11
switch (i)
{
    case 1:
    //... stuff
    break;
    case 2:
    //... stuff
    break;
    default:
    //... stuff
}


有一个GCC扩展可以完全满足您的需要。


std::map::upper_bound+ C + +从11

http:/ / / / / 895245 stackoverflow.com 35460297 lower_bound提到,但我们也可以摆脱的存在(或enum从继承与如果你不拥有它)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <functional>
#include <iostream>
#include <map>

int main() {
    std::string ret;
    const std::map<int,std::function<void()>> 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;
    }
}

输出:

1
2
3
4
5
6
7
8
9
-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

使用方法:用static

使用这种模式,在有效的映射类的初始化,staticallyλ,或其他支付每一次你n log(n)从头开始构建它。

在这里,我们去,与{}CAN初始化静态变量:变量:static方法在类方法,但我们也可以使用该方法描述了在静态构造函数:在C + +?我需要的静态对象的初始化

这是必要的转换到一个上下文捕获[&]λ参数,或是未定义的,将已使用静态常量:λ通过参考与自动捕获

输出的例子是在produces相同:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <functional>
#include <iostream>
#include <map>
#include <string>

class RangeSwitch {
public:
    void method(int x, std::string &ret) {
        static const std::map<int,std::function<void(std::string&)>> 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;
    }
}

本标准不允许:

6.4.2 The switch statement [stmt.switch]

[...] Any statement within the switch statement can be labeled with one or more case labels as follows:

case constant-expression :

where the constant-expression shall be an integral constant expression (5.19).

换言之,您只能使用扩展为单个整型"硬"编译时间常量的case值(例如case 5+6:enum {X = 3}; ... case X*X:)。

解决这个问题的方法是使用if语句。例如,更换

1
2
switch (x)
case 0..100:

你会代替

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

.


这不是开关的工作原理。它只取单个值。如果Elseif挡块你就得用了


我有一个基于分数的问题,尽管"if/elseif"语句很好用,但每隔一段时间,我发现最好的选择(至少对我来说,因为我喜欢它的外观,作为初学者,更容易看到我的错误)是"1…10"。但是不要忘记在数字和点之间使用空格,否则程序会认为你的间隔是一个数字,而你会得到一个错误"2多个小数点…"。希望它有帮助。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int score;

int main()
{
    cout<<"Enter score"<<endl;
    cin>>score;

  switch(score){
    case 100:
        cout<<"Your score is Perfect"<<endl;
    break;
    case 90 ... 99:
        cout<<"You got A"<<endl;
    break;
    case 80 ... 89:
        cout<<"You got B"<<endl;
        break;
    case 70 ... 79:
        cout<<"You got C"<<endl;
        break;
    case 60 ... 69:
        cout<<"You got D"<<endl;
        break;
    case 50 ... 59:
        cout<<"You got E"<<endl;
        break;
    case 0 ... 49:
        cout<<"You got F"<<endl;}

  }


Switch-case不是一个伟大的选择的测试的范围。最好的选择是使用几种if

1
2
3
4
5
6
if (score<0) cout <<"BAD VALUE";
if (score == 0)  cout <<"f";
if (score>0 && score<10) cout <<"e";
if (score>=10 && score <25) cout <<"d";
if (score>=25 && score <50) cout <<"c";
if (score>=50 && score <100) cout <<"b";

如果运行时间是一个问题,以下是更快的解决方案。

1
2
3
4
5
6
7
if (score == 0)  cout <<"f";
else if (score<10) cout <<"e";
else if (score <25) cout <<"d";
else if (score <50) cout <<"c";
else if (score <100) cout <<"b";
else if (score>=100) cout <<"a";
else cout <<"BAD VALUE";


switch case语句是将变量与多个"整型"值进行比较的长if语句的替换("整型"值只是可以表示为整数的值,例如char的值)。switch语句的条件是一个值。案例说明,如果它的值是该案例之后的值,那么就执行结肠后面的任何操作。中断用于中断case语句。

因此,不能在case中使用这种条件语句。

选择结构:开关


这就是我的工作。将标记除以10,然后将大小写10和9设置为显示"A"(这将为90-100之间的任何值显示"A")。然后案例8显示"B",然后案例7将显示"C",表示70-79之间的值,依此类推。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
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;
    }
}

您可以执行以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//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;
//...

}


这是我希望的方式,这是一个简单的CT表现和随访。

你可能会对如何做surprised GCC优化代码,它可以在声音等产生的。我会希望它至少是有效的开关的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>

template<class Value>
struct switcher
{
    constexpr switcher(Value const& value) : value_(value) {}
    constexpr switcher(Value const& value, bool enabled) : value_(value), enabled(enabled) {}

    template<class From, class To, class F>
    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<class F>
    constexpr auto otherwise(F&& f)
    {
        if (enabled)
            f();
    }

    Value const& value_;
    const bool enabled = true;
};

template<class Value>
constexpr auto decision(Value const& value)
{
    return switcher<Value>(value);
}

void test(int x)
{
    decision(x)
            .in_range(0, 10, [&] { std::cout << x <<" maps to option A
"
; })
            .in_range(11, 20, [&] { std::cout << x <<" maps to option B
"
; })
            .otherwise([&] { std::cout << x <<" is not covered
"
; });
}

int main(int argc, char **argv) {

    test(5);
    test(14);
    test(22);
}

我知道这是一个古老的问题,但由于switch声明实际上是围绕标签的包装纸,我发现goto在这里可能(很好)有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    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

这样,您就可以省略所有的else并保持紧凑。不过,在使用goto时应该小心(一般来说)。


像这样?

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

不幸的是,我所知道的没有一个编译器实现这个特定的扩展,尽管gcc可以像其他答案所指出的那样做范围。为了便于携带,您可以剪切和粘贴此dwtfyw许可片段。如果您使用的是自定义枚举,那么您可以使用代码生成来生成类似的东西。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#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

如果您访问ghci(如https://ghc.io/上的在线版本),您可能只需要生成所需内容并将其粘贴到头中,例如。

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

一个潜在的有用见解是,switch接受一个表达式,因此您可以将多个输入值折叠到一个开关盒中。很难看,但考虑到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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;
}

当然,你可以除以5,让EDOCX1(20-24)对EDOCX1(25-29),而不是case 2:内部的if,但是/10可以说更直观。