Как назначить функции указателю на функцию?

#c #c 11

#c #c 11 #c

Вопрос:

Я кодирую эмулятор Gameboy, и для инструкций процессора я использую эту структуру здесь (в cpp.hpp) для хранения информации о них. Карта используется для доступа ко всей этой информации через ключ, равный ее персональному коду операции:

     struct instruction {
        std::string name;    //name of the instruction
        int cycles;          //clock cycles required to be executed
        int paramNum;        //number of params accepted
        void* function;      //code to be executed
    };
    class Cpu {
        private:
            std::map<unsigned char, instruction> instrMap;
            void Cpu::fillInstructions(void);
            instruction addInstruction(std::string, int, int, void*);
        public:
            void add_A_n(unsigned char);
    }
  

Затем в cpu.cpp У меня есть, например, одна из функций, которую я хочу привести к указателю на функцию, чтобы она была назначена полю инструкции struct. Итак, у меня есть этот код:

     void Cpu::add_A_n(unsigned char n) {
        //body     
    }
    void Cpu::addInstructions(std::string name, int cycles, int paramNum, void* function) {
        instruction i = {name, cycles, paramNum, function};
        return i;
    }
    void Cpu::fillInstructions() {
        instrMap[0x80] = Cpu::addInstruction("ADD A, n", 4, 0, (void*)amp;Cpu::add_A_n);
    }
  

Цель состоит в том, чтобы извлечь код операции из памяти, затем использовать этот код операции для извлечения из карты информации об относительной инструкции и, наконец, выполнить ее функцию, используя регистр переключения для выбора правильной:

     ((void (*)(void))instrMap[0x80].function)(); //for 0 params
    ((void (*)(unsigned char))instrMap[0x90].function)((unsigned char)operand); //for 1 param
  

Моя цель — привести все функции, даже те, которым требуются некоторые параметры, к той, что находится в структуре.

Соответствующая функция выполняется корректно, но выдается предупреждение:

предупреждение: преобразование из ‘void (Cpu::)()’ в ‘void‘ [-Wpmf-conversations] instrMap[0x80] = Cpu::addInstruction(«ДОБАВИТЬ A, n», 4, 0, (void*)amp;Cpu::add_A_n);

Как я могу это решить и почему это происходит? Спасибо

Комментарии:

1. Я не думаю, что это лучший способ реализовать эмулятор процессора, потому что вы теряете безопасность типов, передавая указатели на функции как void* . Думали ли вы об использовании структуры для хранения параметров, переданных virtual функции в подклассе, который вместо этого представляет инструкцию?

2. Непрошеный совет: используйте std::unordered_map , если вам не нужен порядок в вашей карте, чего вы, вероятно, не делаете. (В настоящее время также ожидается создание плоской карты в стандарте и в flat_hash_map от Google.)

3. @metal Для этого требуется C 11, но мне, вероятно, потребуется его использовать.

4. Вы также можете получить совместимую с C 98 хэш-карту из boost::unordered_map , из которой была получена версия std.

Ответ №1:

amp;Cpu::add_A_n возвращает указатель на функцию-член, который сильно отличается от обычного указателя на функцию, и их нельзя смешивать. Странность, связанная с указателем на функции-члены, заключается в том, что всем нестатическим функциям-членам требуется this экземпляр для вызова функции.

В вашем случае, если функция, подобная add_A_n действительно не зависит от this , просто создайте ее static или функцию, не являющуюся членом:

 class Cpu {
    ...
    static add_A_n(unsigned char);
};
  

Таким образом, больше не требуется this вызывать a, и amp;Cpu::add_A_n он становится обычным указателем на функцию.