C++:switch语句中的struct成员

dco*_*ill 8 c++ struct visual-c++ constexpr c++11

我正在用C++编写一个微处理器模拟器,我的目标之一是使代码非常易读.为了实现操作码,我有一个结构,我用它来表示单独的处理器指令,它包含操作码和程序计数器的推进程度.我们的想法是将有关每条指令的相关信息分组.

struct instruction
{
    const int opcode; // instruction opcode
    const int op_size; // how far to advance Program Counter
};

const instruction HALT{0x76, 1};
const instruction NOP {0x00, 1};
Run Code Online (Sandbox Code Playgroud)

我最初的计划是使用这个结构来定义所有的操作码,因为我认为const它更适合#define用于C++常量.此外,我将能够干净地分组操作码的所有相关属性.

但是,似乎这对于switch语句不起作用,正如我最初的意图.以下代码将无法编译,Visual Studio将提供错误"case expression not constant".

switch (next_instruction) { // next_instruction is an int parsed from a file
    case HALT.opcode:
        // do stuff
        break;
    case NOP.opcode:
        // do stuff
        break;
    default:
        std::cout << "Unrecognized opcode" << std::endl;
            break;
    }
Run Code Online (Sandbox Code Playgroud)

我还下载了最新的Visual Studio编译器(MSVC 2013年11月CTP)以尝试利用constexprC++ 11,但我遇到了同样的问题,并且它无法编译.在这里,我将我的结构转换为一个类并尝试利用constexpr,以确保一个成员instruction可以用作编译时常量.

class Instruction
{
  public:
    constexpr Instruction(int code, int size) : opcode(code), op_size(size) {}
    const int opcode; // instruction opcode
    const int op_size; // how far to advance Program Counter
};

constexpr Instruction HALT(0x76, 1);
constexpr Instruction NOP (0x00, 1);
Run Code Online (Sandbox Code Playgroud)

我现在不确定该怎么做,因为看起来编译器不理解struct值被指定为常量.

那么有没有办法在switch语句中使用struct成员,或者我应该切换到使用#define?或者,有没有更好的方法来做到这一点,同时仍然保留一些组织?我非常感谢您提供的任何帮助或见解,谢谢!

编辑:对不起,我应该更清楚地说明next_instruction只是一个int,而不是一个instructionstruct/object

dav*_*daf 10

我已经使用MinGW 4.8.3编译器在Qt Creator 3.1.2中测试了你的代码.只需在每个指令定义中用constexpr替换const就可以使编译器满意:

struct instruction
{
    const int opcode; // instruction opcode
    const int op_size; // how far to advance Program Counter
};

// Replacing "const" by "constexpr" int these two lines
constexpr instruction HALT{0x76, 1};
constexpr instruction NOP {0x00, 1};

int main() {
    int next_instruction = 0x76;
    switch (next_instruction) { // next_instruction is an int parsed from a file
        case HALT.opcode:
            // do stuff
            break;
        case NOP.opcode:
            // do stuff
            break;
        default:
            std::cout << "Unrecognized opcode" << std::endl;
                break;
        }
}
Run Code Online (Sandbox Code Playgroud)

编辑以添加一些引号:

C++编程语言(Fourh Edition)讲述了switch语句中的标签:

" 案例标签中的表达式必须是 整数或枚举类型的常量表达式."(9.4.2开关声明").

从第10.4节常量表达式:

C++提供了"常量"的两个相关含义:

  • constexpr:在编译时进行评估
  • const:不要在此范围内修改

基本上,constexpr的作用是启用并确保 编译时评估,而const的主要作用是指定接口中的不变性.

[...]

10.4.2常量表达式中的常量

[...]用常量表达式初始化的const可用于常量表达式.const与constexpr的不同之处在于它可以通过不是常量表达式的东西来初始化; 在这种情况下,const不能用作常量表达式.

switch语句中的标签需要constexpr,以便在编译时完成评估.所以似乎const instruction HALT {0x76,1}不能确保编译时评估constexpr instruction HALT {0x076,1}.


Abh*_*jit 5

如果您不想使用模板进行冒险,那么没有可怕宏的可能解决方案可能如下所示.

template<int code, int size>
struct InstructionType
{
    static const int opcode = code ;
    static const int op_size = size;
};
struct Instruction 
{
    int opcode;
    int op_size;
};
typedef  InstructionType<0x76, 1> HALT;
typedef  InstructionType<0x00, 1> NOP;


int main()
{
    Instruction next_instruction;
    switch (next_instruction.opcode) {
    case HALT::opcode:
        // do stuff
        break;
    case NOP::opcode:
        // do stuff
        break;
    default:
        std::cout << "Unrecognized opcode" << std::endl;
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)