Вы можете сделать несколько хитрых трюков, чтобы получить сигнатуру лямбды и использовать ее для получения компонентов.
template <typename Class, typename... Params>
void mod_comp_helper(Entity ent, Class *obj, void (Class::*fun)(Params...) const) {
(obj->*fun)(get_comp<std::decay_t<Params>>(ent)...);
}
// optional overload for mutable lambdas
template <typename Class, typename... Params>
void mod_comp_helper(Entity ent, Class *obj, void (Class::*fun)(Params...)) {
(obj->*fun)(get_comp<std::decay_t<Params>>(ent)...);
}
template <typename Functor>
void mod_comp(Entity ent, Functor &&fun) {
mod_comp_helper(ent, &fun, &std::decay_t<Functor>::operator());
}
// optional overload for function pointers
template <typename... Params>
void mod_comp(Entity ent, void(*fun)(Params...)) {
fun(get_comp<std::decay_t<Params>(ent)>...);
}
int main() {
mod_comp(ent, [](Velocity &vel, Position &pos) {
// modify components
});
// you can use std::function if you want
// although you probably don't need to
std::function<void(Velocity &, Position &)> fun = [](Velocity &vel, Position &pos) {
// modify components
};
mod_comp(ent, fun);
// this calls the function pointer overload
mod_comp(ent, +[](Velocity &vel, Position &pos) {
// modify components
});
}
Лямбда-выражение на самом деле является просто синтаксическим сахаром для создания функтора (объекта соператор вызова).
struct __anonymous_compiler_generated_class__ {
void operator()(int i) const {
// ...
}
};
int main() {
auto lambda = [](int i) {
// ...
};
// above is sugar for this:
auto functor = __anonymous_compiler_generated_class__{};
}
Лямбда-выражение создает объект замыкания.Этот объект имеет operator()
.Мы можем взять адрес оператора звонка и вывести его подпись.Затем мы просто std::decay_t
типы параметров для удаления ссылок и константности.
Еще один хитрый трюк с лямбдами - это преобразование их в указатели на функции (что я показал в первом примере).Неполные лямбды могут быть неявно преобразованы в указатели функций.Вы можете использовать унарный +
или static_cast
для принудительного преобразования.Вот еще несколько примеров этого:
int main() {
auto lambda = [](int i) {};
void (*fnptr0)(int) = lambda;
auto fnptr1 = +lambda;
auto fnptr2 = static_cast<void(*)(int)>(lambda);
int capture;
auto capturing_lambda = [capture](int i) {};
// compiler says no
// auto fnptr3 = +capturing_lambda;
}
Если вам не требуется захват лямбд и вы можете допустить унарный +
, тогда вы можете просто использовать перегрузку указателя функции mod_comp
, но для этогоВы, вероятно, хотите захватить лямбды.