如何在一个switch中实现多个case的一些独占语句和一些公用语句?

How to achieve some exclusive statements and some common statements for multiple cases in a switch?

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

编辑:代码示例

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;
  • 将标志设置为 true
  • 在switch的默认情况下,设置flag为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);

保持 std::mapcharcommand.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);
}

I have a switch statement where each case has unique code, and some code that is shared between all cases except the default label.

对于您的特定示例案例,不同案例之间的唯一区别在于数据而非执行,地图可能更合适(参见 )。

一般来说,当映射不合适时(即当代码路径在执行时不同时),您可以使用这种很少使用的基本控制结构,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:
//...

这比标志变量更清晰易读 - 虽然这只是我的意见。

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

#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');
}

我们可以在不实际使用的情况下产生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;        
}