Отключение предупреждения о "плохой функции"

Я получаю следующее предупреждение:

warning: converting from 'void (MyClass::*)(byte)' to 'void (*)(byte)'

Это потому, что мне нужно передать в качестве аргумента функцию-член вместо обычной функции. Но программа работает правильно.

Я хочу отключить это предупреждение (Wno-bad-function-cast не работает для С++) или реализовать другой способ передачи функции-члена.

Ответ 1

Нет. Примите это предупреждение всерьез. Вы должны скорее изменить свой код для обработки этого сценария.

Указатель на функцию-член (void (MyClass::*)(byte)) и указатель нормальной функции (void (*)(byte)) совершенно разные. См. эту ссылку. Вы не можете бросить их именно так. Это приводит к undefined поведению или сбою.

Смотрите здесь, как они отличаются:

void foo (byte); // normal function
struct MyClass {
  void foo (byte); // member function 
}

Теперь вы можете почувствовать, что foo(byte) и MyClass::foo(byte) имеют одну и ту же подпись, тогда почему их указатели на функции НЕ совпадают. Это потому, что MyClass::foo(byte) внутренне разрешено несколько, как

void foo(MyClass* const this, byte);

Теперь вы можете почувствовать разницу между ними.

Объявить указатель на функцию-член как,

void (MyClass::*ptr)(byte) = &MyClass::foo;

Вы должны использовать этот ptr с объектом MyClass, например:

MyClass obj;
obj.*ptr('a');

Ответ 2

Вы не можете передать функцию, которая принимает два аргумента в место, которое ожидает функцию, которая занимает один. Не может быть сделано, забудьте об этом, периоде, конце истории. Вызывающий передает один аргумент вашей функции. Он не знает о втором аргументе, он не передает его вашей функции, вы не можете заставить его делать то, что вы хотите, но как бы вы ни старались.

По той же причине вы не можете передать нестационарную функцию-член, где ожидается регулярная функция. Для функции-члена нужен объект для работы. Независимо от того, какой код вызывает вашу функцию, он не знает об объекте, нет способа передать ему объект, и нет способа заставить его использовать правильную последовательность вызовов, которая учитывает объект.

Интерфейсы, которые выполняют функции пользователя, не беря дополнительных данных, которые пользователь может захотеть передать своей функции, по своей сути являются злыми. Посмотрите на функцию qsort() из стандартной библиотеки C. Это пример злого интерфейса. Предположим, вы хотите отсортировать массив строк в соответствии с некоторой схемой сортировки, определенной извне. Но все, что он принимает, является функцией сравнения, которая принимает два значения. Как вы передаете эту схему сопоставления своей функции сравнения? Вы не можете, и поэтому, если вы хотите, чтобы он работал, вы должны использовать злую глобальную переменную со всеми привязанными к ней строками.

Вот почему С++ отошел от прохождения указателей функций и в объектов функции. Объекты функции могут инкапсулировать любые данные, которые вы хотите.

Ответ 3

Кроме того, этот может быть полезен

union FuncPtr    
{
  void (* func)(MyClass* ptr, byte);
  void (MyClass::* mem_func)(byte);
};