【问题标题】:How to achieve some exclusive statements and some common statements for multiple cases in a switch?如何在一个switch中实现多个case的一些独占语句和一些通用语句?
【发布时间】:2017-04-21 14:44:13
【问题描述】:

我有一个switch 语句,其中每个案例都有唯一的代码,以及除默认标签之外的所有案例之间共享的一些代码。 有没有一种在不同案例标签之间共享命令的好方法?

编辑:代码示例

switch (c)
{
    case '+':
        command.type = ADD;
        commands.push_back(command);
        break;
    case '-':
        command.type = SUB;
        commands.push_back(command);
        break;
    case '>':
        command.type = INC;
        commands.push_back(command);
        break;
    case '<':
        command.type = DEC;
        commands.push_back(command);
        break;
    case '.':
        command.type = PUT;
        commands.push_back(command);
        break;
    case ',':
        command.type = GET;
        commands.push_back(command);
        break;
    default: break;

【问题讨论】:

  • 您也许可以将代码重构为函数。你能分享一个代码示例吗?
  • 如果在所有情况下都共享,请将其放在开关之前(或之后)。
  • 如果您的意思是对每个 switch 案例执行相同的语句,则 Switch 案例会失败。
  • 显示你的代码!
  • 把 switch 语句改成这样:return_type func(container&amp; cmd, const type option /* ADD, SUB, etc. */)

标签: c++ c switch-statement goto


【解决方案1】:

std::mapchar 保留为command.type 的任何类型。
我们就叫它command_table吧。

然后:

switch (c)
{
    case '+':
    case '-':
    case '>':
    case '<':
    case '.':
    case ',':
        command.type = command_table[c];
        commands.push_back(command);
        break;
    default: break;
}

或者,更短,并且具有更难忘记案例的额外好处:

auto it = command_table.find(c);
if (it != command_table.end())
{
    command.type = it.second;
    commands.push_back(command);
}

【讨论】:

  • 如果你有地图那么你不需要开关
  • “我们称它为commands。” 或者我们称它为与已定义的名为commands 的向量不冲突的东西。
  • 在这种情况下绝对更干净更短
【解决方案2】:
  • 将标志设置为真
  • 在开关的默认情况下,将标志设置为false
  • 如果标志为真,则运行公共代码。

类似于以下内容:

bool MyPushBackFlag = true;
switch (c)
{
    case '+':
        command.type = ADD;
        break;
    case '-':
        command.type = SUB;
        break;
    case '>':
        command.type = INC;
        break;
    case '<':
        command.type = DEC;
        break;
    case '.':
        command.type = PUT;
        break;
    case ',':
        command.type = GET;
        break;
    default: MyPushBackFlag = false; break;
}

if (MyPushBackFlag)
     commands.push_back(command);

【讨论】:

  • if( flag == true ) 我讨厌这个:(
  • @Slava 对于我们来说很明显if(MyPushBackFlag) 可以工作,但是对于 OP :(
  • @Slava 你讨厌它并不意味着它不好。
  • @KyleKhalaf 不必要的冗长代码是不好的,而 if( pointer != nullptr ) 而不是 if( pointer ) 可以增加可读性,与 if 内部的 true 相比是没用的。你也可以写if ( ( flag == true ) == true ),何不给true加个比较呢?
  • @Slava 这只是您的偏好。在任何编程语言中看到if(flag == true) 时,程序员的困惑是忽视。我的偏好是逻辑比亲身体验语法要好。我会在语法之前教我的孩子逻辑。 OP(学生)需要在这里学习一些逻辑
【解决方案3】:

有时重构代码只会增加复杂性... :)

#include <vector>
#include <array>
#include <iostream>

enum CommandType {
    ADD, SUB, INC, DEC, PUT, GET
};

struct Command {
    CommandType type;
};

std::vector<Command> commands;

using mapping = std::pair<char, CommandType>;

template<class T, class Iter, class Func>
bool dispatch(T &&t, Iter first, Iter last, Func &&f) {
    auto i = std::find_if(first, last, [&t](auto &&pair) { return std::get<0>(pair) == t; });
    if (i == last) {
        return false;
    }
    f(std::get<1>(*i));
    return true;
}

template<class T, std::size_t N, class Func>
bool dispatch(char t, std::array<mapping, N> const &range, Func &&f) {
    return dispatch(t, range.begin(), range.end(), std::forward<Func>(f));
}

bool my_switch(char c) {

    return dispatch(c,
                    std::array<mapping, 6> {{
                                                    {'+', ADD},
                                                    {'-', SUB},
                                                    {'>', INC},
                                                    {'<', DEC},
                                                    {'.', PUT},
                                                    {',', GET}
                                            }}, [](auto type) {
                Command command{};
                command.type = type;
                commands.push_back(command);
                std::cout << "dispatched: " << command.type << std::endl;
            })
           or [](char c) { 
        std::cout << "invalid option " << c << std::endl;
        return false;
    }(c);
}


int main() {
    my_switch('+');
    my_switch('<');
    my_switch('U');
}

【讨论】:

    【解决方案4】:

    我有一个 switch 语句,其中每个案例都有唯一的代码,以及一些代码在所有案例之间共享,除了默认标签。

    对于您的特定示例案例,不同案例之间的唯一区别在于数据而不是执行,映射可能更合适(请参阅molbdnilo's answer)。

    一般来说,在不适合映射的情况下(即当代码路径在执行时不同),您可以使用这种很少使用的原始控制结构goto

    switch( c )
    {
        case '+': command.type = ADD; break;
        case '-': command.type = SUB; break;
        case '>': command.type = INC; break;
        case '<': command.type = DEC; break;
        case '.': command.type = PUT; break;
        case ',': command.type = GET; break;
        default:
            goto no_match; // or return from function if appropriate
    }
    commands.push_back( command );
    no_match:
    //...
    

    这比标志变量更清晰、更容易阅读——尽管这只是我的看法。

    【讨论】:

    • @谁投了反对票,你怎么觉得答案没有帮助?您有改进的建议吗?
    • 我没有投反对票,但在阅读您的回答后我想到的第一件事是:stackoverflow.com/a/379259/1133284
    • 虽然该解决方案将起作用,但它远非惯用语,并且涉及使用在大多数人列表中低于底部的语言功能。我只是在这里看不到任何价值。
    • 在这种情况下使用goto 比其他方法更简单、更干净、更高效。但是我们宁愿跳过荒谬的圈子来避免它,因为我们太害怕它了?
    【解决方案5】:

    我们可以在不实际使用的情况下产生goto 的效果。

    #define GOTO_END(...) { __VA_ARGS__; } if(false)
    #define END {}
    switch(c)
    {
      case '+': GOTO_END(command.type = ADD)
      case '-': GOTO_END(command.type = SUB) // if `c == '-'` then jump to END
      case '>': GOTO_END(command.type = INC)
      case '<': GOTO_END(command.type = DEC)
      case '.': GOTO_END(command.type = PUT)
      case ',': GOTO_END(command.type = GET)
                END // <--- must not be forgotten
                commands.push_back(command);
      default:  break;        
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-18
      • 2021-02-19
      • 2019-04-07
      相关资源
      最近更新 更多