Указатель на функцию не присваивается массиву указателей на функции

#c #function-pointers

#c #указатели на функции

Вопрос:

После удаления всех определений типов у меня есть следующие объявления:

 class Message {
  protected:
    Message* (*factories[N])(HardwareSerial);
    ...
}

class DebugMessage : Message {
  protected:
    Message* receive(HardwareSerial serial);
    ...
  public:
    DebugMessage(char* message);
    ...
};

Message* DebugMessage::receive(HardwareSerial serial){...}

DebugMessage::DebugMessage(char* message){
  ...
  factories[DEBUG_MESSAGE] = amp;DebugMessage::receive;
  ...
}
  

Однако, когда я пытаюсь его скомпилировать, я получаю сообщение об ошибке при назначении с указанием

 debugMessage.cpp: In constructor ‘DebugMessage::DebugMessage(char*)’:
debugMessage.cpp:4:28: error: cannot convert ‘Message* (DebugMessage::*)(HardwareSerial)’ to ‘Message* (*)(HardwareSerial)’ in assignment
   factories[DEBUG_MESSAGE] = amp;DebugMessage::receive;
  

Ответ №1:

Вам нужно уточнить точный тип указателя на функцию, который вам нужно сохранить в вашем массиве:

 class Message {
  protected:
    Message* (DebugMessage::*factories[N])(HardwareSerial);
    ...
}
  

ОБНОВЛЕНИЕ (немного подробнее)

Причина такого уточнения типа данных заключается в том, что функции-члены имеют дополнительный (скрытый) первый параметр this , о котором компилятор должен знать при вызове его через указатель на функцию.

Сказав это, я должен указать, что static функции-члены не имеют такого ограничения (поскольку у них нет this параметра) и могут быть «свободно смешаны» со свободными функциями в этом отношении

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

1. Исправление: указатели на свободные функции и указатели на функции-члены — это разные типы.

Ответ №2:

@YePhlcK объяснил, почему у вас возникла проблема, но я не знаю, действительно ли опубликованный им код решает проблему. Я думаю, что вы сможете добавлять указатели на DebugMessage функции-члены только как фабрики, используя это. Я изменил ваш код, чтобы он компилировался и использовался std::function , и std::bind чтобы получить указатель функции на функцию-член.

 #include <functional>

class HardwareSerial {};

class Message {
public:
    using Reciever = Message*(HardwareSerial);
protected:
    std::function<Reciever> factories[10];
};

class DebugMessage : Message {
protected:
    Message* receive(HardwareSerial serial);
public:
    DebugMessage(char* message);
};

Message* DebugMessage::receive(HardwareSerial serial){ return nullptr; }

DebugMessage::DebugMessage(char* message){
    factories[0] = std::bind(amp;DebugMessage::receive, this, std::placeholders::_1);
}
  

Таким образом, в вашем массиве могут быть функции-члены и функции, не являющиеся членами, а также лямбды и функциональные объекты. Вам нужно использовать только std::bind с функциями-членами.

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

1. Оба эти ответа были действительно хорошими. Если бы кто-нибудь нашел этот вопрос, я бы порекомендовал им кодировать таким образом. При этом я выбрал другой ответ, потому что он прямо ответил на мой вопрос (даже если это менее правильный способ кодирования).