В общем, если вы не используете приведение, вам следует доверять g ++.
Хотя верно, что ни один из упомянутых вами типов функций не может быть экспортирован для использования изнутри C, это не то, о чем вы спрашиваете. Вы спрашиваете, какие функции можно передавать в качестве указателя на функцию.
Чтобы ответить, что вы можете пройти, я думаю, что более конструктивно понять, что вы не можете пройти. Вы не можете передать ничего, что требует дополнительных аргументов, явно не указанных в списке аргументов.
Итак, никаких нестатических методов. Им нужно неявное «это». C не знает, как пройти. Опять же, компилятор вам не позволит.
Никаких лямбд. Им требуется неявный аргумент с фактическим телом лямбда.
Вы можете передавать указатели на функции, которые не требуют неявного контекста. Фактически, вы пошли дальше и перечислили их:
- Указатель на функцию. Неважно, стандартная это функция или шаблон, если шаблон полностью разрешен. Это не является проблемой. Любой написанный вами синтаксис, который приводит к указателю на функцию, автоматически полностью разрешит шаблон.
- Не захватывающие лямбды. Это специальный обходной путь, представленный C ++ 11, когда он представил лямбда-выражения. Поскольку это возможно, компилятор выполняет явное преобразование, необходимое для этого.
- Статические методы. Поскольку они статичны, им не передается неявный
this
, поэтому с ними все в порядке.
Последний требует дальнейшего развития. Многие механизмы обратного вызова C получают указатель на функцию и void * opaq. Следующее является стандартным и достаточно безопасным для использования с классом C ++:
class Something {
void callback() {
// Body goes here
}
static void exported_callback(void *opaq) {
static_cast<Something*>(opaq)->callback();
}
}
А затем сделайте:
Something something;
register_callback(Something::exported_callback, &something);
Отредактировано для добавления: единственная причина, по которой это работает, заключается в том, что соглашение о вызовах C ++ и соглашение о вызовах C идентичны, когда не передаются неявные аргументы. Есть разница в изменении имени, но это не имеет значения, когда вы передаете указатель на функцию, поскольку единственная цель изменения имени - позволить компоновщику найти правильный адрес функции.
Если бы вы попробовали этот трюк с обратным вызовом, ожидающим, например, соглашения о вызовах stdcall или паскаль, эта схема потерпела бы неудачу.
Однако это характерно не только для статических методов, лямбда-выражений и шаблонных функций. При таких обстоятельствах даже стандартная функция не сработает.
К сожалению, когда вы определяете указатель функции на тип stdcall, gcc игнорирует вас:
#define stdcall __attribute__((stdcall))
typedef stdcall void (*callback_type)(void *);
приводит к:
test.cpp:2:45: warning: ‘stdcall’ attribute ignored [-Wattributes]
typedef stdcall void (*callback_type)(void *);
person
Shachar Shemesh
schedule
29.04.2016