在vector中调用函数指针没有任何作用

时间:2019-04-02 14:22:50

标签: c++ function-pointers

我当前正在尝试实现CHIP-8仿真器。在这些仿真器中,您将读取盒带的内容,该盒带将为您提供与功能相对应的“操作码”值。我不想编写庞大的switch case语句来处理这些操作码(在CHIP-8模拟器的上下文中,这是可以的,因为没有太多的操作码,但是在Gameboy模拟器的上下文中,例如,它可以产生一些巨大的switch case语句)。

我的方法如下:

我有一个结构,其中包含操作码范围,函数名称和函数指针(void* func)。

struct instruction {
    std::pair<uint16_t, uint16_t> range;
    std::string name;
    void* func;

    instruction(std::pair<uint16_t, uint16_t> range, std::string name, void* func) {
        this->range = range;
        this->name = name;
        this->func = func;
    }
};

我的班级看起来像这样(请不要打我,我现在把所有内容public都放了,但是当一切正常的时候,它们会变成私有的):

class Chip8 {
    public:
        Chip8();
        virtual ~Chip8();

        void set_opcodes(void);

        bool load_cartridge(std::string path);
        void output_cartridge_contents(void);
        bool verifiy_instructions(void);

        void JUMP(void);

        // 0     -> 0x1FF: interpreter (unused since the emulator is running outside of the memory)
        // 0x200 -> 0xE9F: cartridge data
        // 0xEA0 -> 0xEFF: call stack, internal use, and other variables
        // 0xF00 -> 0xFFF: display refresh
        std::vector<uint8_t> memory;
        std::vector<uint8_t> registers;

        // Index register
        uint16_t I;
        // Program counter
        uint16_t pc;

        std::vector<uint8_t> stack;
        // Stack pointer
        uint8_t sp;

        std::vector<instruction> instr;

        // Timers
        uint8_t delay_timer;
        uint8_t sound_timer;

        uint16_t opcode;

        // Screen
        bool gfx[64 * 32];

};

让我们以JUMP为例吧

void Chip8::JUMP(void) {
    this->pc = (this->opcode & 0x0FFF);
}

然后我要填充一个包含所有已实现操作码的向量,

this->instr.push_back(instruction(std::pair<uint16_t, uint16_t>(0x1000,0x1FFF), std::string("JUMP"), (void*)&Chip8::JUMP))

读取当前操作码,然后将其与实现的功能范围进行比较(例如,如果操作码为0x1225,则将调用JUMP函数)。找到正确的函数后,将调用以下代码(i是上面显示的instruction向量中正确的instr的索引):

this->instr[i].func;

但是,当我这样做时,什么也没发生(即pc的值不变,std::cout在控制台上什么也没有产生,等等)。我尝试了多种方法(将func的类型更改为void (*func)(void),尝试调用this->instr[i].func();),但到目前为止还没有碰到运气。我想我在这里错过了一些东西。任何人都有一些指针吗?

谢谢

2 个答案:

答案 0 :(得分:5)

由于Chip8::JUMP是一个非静态的类成员函数,因此您需要一个类的对象来调用该函数。这是因为非静态成员函数具有类类型的隐式第一个参数,该参数用于启用在函数内部使用this

您可以通过使用std::function并使用lambda或std::bind将函数绑定到对象来解决此问题。看起来像

struct instruction {
    std::pair<uint16_t, uint16_t> range;
    std::string name;
    std::function<void(void)> func;

    template<typename Func>
    instruction(std::pair<uint16_t, uint16_t> range, std::string name, Func func) : range(range), name(name), func(func) {}
};

//...

this->instr.push_back(instruction(std::pair<uint16_t, uint16_t>(0x1000,0x1FFF), std::string("JUMP"), [this]{ this->JUMP(); }))

// and call it like

this->instr[i].func();

答案 1 :(得分:1)

  

指向函数(void* func)的指针。

void *不是函数的指针。它是指向对象的指针。

(void*)&Chip8::JUMP

这是一个糟糕的演员表。成员函数指针不能有效地转换为void*。通过转换后的指针进行间接操作将具有不确定的行为(即使转换回正确的类型也是如此)。

this->instr[i].func;
     

但是当我这样做时,什么也没发生

this->instr[i].func;不是函数调用表达式。这是一个id表达式。 id表达式没有副作用。

所有函数调用表达式的括号都包含(可能为空)参数列表。

  

我尝试了多种方法(将func的类型更改为void (*func)(void)

void (*func)(void) 一个函数指针。但这不是成员函数指针。您不能将&Chip8::JUMP转换为函数指针。

  

尝试致电this->instr[i].func();

这是一个函数调用表达式,因此您越来越近了。这将是函数指针的正确语法,但是您已尝试使用非静态成员函数,因此函数指针对您不起作用。


您可以将instruction做成模板,并使用成员函数指针:

template<class T>
struct instruction {
    void (T::*func)(); // a pointer to member function
    // ...
};

// insert
instr.emplace_back(/* other member initializers */, &JUMP);

// call
(this->*(instr[i].func))()