Случай без захвата
Как указывают комментаторы, лямбда неявно преобразуется в указатель на функцию соответствующего типа, поэтому мы можем просто написать:
auto my_lambda = [](void* data) { /* do stuff here */};
register_callback(my_lambda, get_pointer_to_data());
и это скомпилируется. Не забудьте проверить возвращаемое значение: -)
Футляр для захвата
Вот что я сейчас делаю, но я подозреваю, что это неоптимально.
Сначала я проверяю, что лямбда захватывает все, что ему нужно, чтобы он сам вызывался с параметрами без (так что на самом деле не принимает void*
как обратный звонок должен). Тогда я использую этот код:
template <typename Invokable>
void callback_adapter(void *invokable_on_heap)
{
auto retyped_callback = std::unique_ptr<Invokable>{
reinterpret_cast<Invokable*>(invokable_on_heap)
};
(*retyped_callback)(std::forward<Ts>(parameters)...);
// Note: invokable_on_heap will be delete'd
}
template <typename Invokable>
void register_invokable_as_callback(Invokable callback_) {
Invokable* invokable_on_the_heap = new Invokable(std::move(callback_));
register_callback(&callback_adapter<Invokable>, invokable_on_the_heap);
}
Примечание: При таком подходе обратный вызов может быть вызван только один раз. Его можно адаптировать к случаю обратного вызова, который необходимо вызывать много раз, с освобождением после отмены регистрации / уничтожения того, для чего требуется обратный вызов.