0
votes

Problem

I have an array of member function pointers that I assign at run-time. I am getting a compile-time error when attempting to call them:

pointer to member type 'void (YCPU::)(uint16_t)' {aka 'void (YCPU::)(short unsigned int)'} incompatible with object type 'YCPUInstruction'`

I'm having trouble understanding the proper syntax to call the pointers.

Code and Problem Details

I have a struct YCPUInstruction that stores two member function pointers. These function pointers point to member functions inside YCPU. I store an array of YCPUInstructions and during initialization I call initialize which assigns these pointers to the correct member function.

Member function pointers and YCPUInstruction:

typedef void (YCPU::*YCPUOpcode)(uint16_t opcode);
typedef std::string (YCPU::*YCPUDisassembler)(std::string name, uint16_t operand, uint16_t nextword, uint16_t address,
                                              bool show_memory_contents, uint16_t &instruction_size);


struct YCPUInstruction {
    std::string name;

    static YCPUOpcode opcode;
    static YCPUDisassembler disassembler;

    int cycles;
    bool is_nop;

    void initialize(std::string name, YCPUOpcode opcode, YCPUDisassembler disassembler, int cycles, bool is_NOP = false)
    {
        this->name = name;
        this->opcode = opcode;
        this->disassembler = disassembler;
        this->cycles = cycles;
        this->is_nop = is_NOP;
    }
};

YCPU

class YCPU
{
public:
    // YCPUOpcode points to one these functions (many more than these 3, just examples)
    void NOP(uint16_t opcode);
    void ADC(uint16_t opcode);
    void ADD(uint16_t opcode);
    ...
    // YCPUDisassembler points to one of these functions (many more than these 2, just examples)
    std::string disassemble_ALU(std::string name, uint16_t operand, uint16_t nextword, uint16_t address,
                             bool show_memory_contents, uint16_t &instruction_size);
    std::string disassemble_BRA(std::string name, uint16_t operand, uint16_t nextword, uint16_t address,
                             bool show_memory_contents, uint16_t &instruction_size);
    ...
private:
    std::array<YCPUInstruction, 256> opcodes;
};

During setup, I initialize the opcodes like so:

void YCPU::initialize_opcodes()
{
    opcodes[0x01].initialize("CMP", &YCPU::CMP, &YCPU::disassemble_ALU, 0);
    opcodes[0x02].initialize("CMP", &YCPU::CMP, &YCPU::disassemble_ALU, 0);
    opcodes[0x03].initialize("CMP", &YCPU::CMP, &YCPU::disassemble_ALU, 0);
    ... // and so on for all instructions 
}

After initialization, I attempt to call the member functions like so:

void YCPU::run_one_instruction()
{
    ...
    uint16_t word = read_mem_int16(PC, SI_CS); // 0x1-0xff
    YCPUInstruction op = opcodes[word & 0xFFFF];
    (op.*YCPUInstruction::opcode)(word);
    ...
}

However, that throws the compiler error I mentioned above.

If I dereference op first, like so:

(op->*YCPUInstruction::opcode)(word);

I get this error:

error: no match for 'operator->*' (operand types are 'YCPUInstruction' and 'YCPUOpcode' {aka 'void (YCPU::*)(short unsigned int)'})

If I change the syntax to this:

(op->*opcode)(word);

or:

(op.*opcode)(word)

I get this error

error: 'opcode' was not declared in this scope

What is the specific syntax I need to use to call these member function pointers?

1
Based on your error message, it sounds like you're trying to use a YCPUInstruction instead of a YCPUOpcode. What type is op?Stephen Newell
op is a YCPUInstruction. Apologies I'll update the code to show it's type and how it gets assigned0x003
Those types describe functions which are members of YCPU. So what is the YCPU object which you want this to point at inside those functions?aschepler
You've defined opcode as static, yet you're trying to treat it as a member variable. Which is it meant to be?Ken Wayne VanderLinde
@KenWayneVanderLinde any chance you could link me some information on the difference? I was just listening to my IDE and forgot I added that identifier. YCPU is the parent object that stores op and calls it0x003

1 Answers

1
votes

The left operand of .* must refer to / the left operand of ->* must point at an object of the member function's containing class. The right operand can be any expression which gives the pointer-to-member value.

The containing class of the member functions you're using is YCPU, so it's not correct to have the YCPUInstruction as a left operand. I see that your expression is within another member function of YCPU, so assuming you want to use *this as the YCPU the function is called on, you want this->*. The following expression can be an ordinary . or -> expression to just get, not call, the pointer-to-member-function value from the YCPUInstruction. Since the precedence of .* and ->* are strange, excessive parentheses are quite often necessary and always recommended.

void YCPU::run_one_instruction()
{
    // ...
    uint16_t word = read_mem_int16(PC, SI_CS); // 0x1-0xff
    YCPUInstruction op = opcodes[word & 0xFFFF];
    (this->*(op.opcode))(word);
    // ...
}