使用lambda修改由packed参数标识的引用?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用lambda修改由packed参数标识的引用?相关的知识,希望对你有一定的参考价值。
我正在尝试在WIP小“游戏框架”中创建实体组件的一个很好的修改功能。但是,在尝试修改多个组件时,我仍然坚持创建该函数(使用压缩参数)
这是我对单个组件的功能,它可以正常工作并且按我喜欢的方式运行
template <typename C>
void mod_comp(Entity ent, std::function<void(C&)> cb) {
auto& c = get_comp<C>(ent);
return cb(c);
}
// Called like this
mng.mod_comp<Velocity>(ent, [](auto& vel) {
// Modify velocity force value
vel.f += 5;
});
在尝试为多个组件创建函数时,我发现了2个问题,我无法弄清楚如何解决。
template <typename... C>
void mod_comp(Entity ent, std::function<void(C...)> cb) {
return cb(get_comp<C>(ent)...);
}
// Supposed to be called like this
mng.mod_comp<Velocity, Position>(ent, [](Velocity vel, Position pos) {
pos.x += vel.f;
});
但是,即使打包参数...C
(Velocity, Position
)匹配lambda(Velocity, Position
)中的参数,这也会产生“无匹配错误”。我无法解决这个问题。
然而,主要的问题是,如果lambda参数可以简化为像单个mod函数,如this([](auto& vel, auto& pos)
,也可以作为参考转发。我觉得这应该是可能的,因为编译器不知道什么,但我的C ++是有限的。
你可以做一些偷偷摸摸的技巧来获得lambda的签名并用它来获取组件。
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
});
}
lambda表达式实际上只是用于构造仿函数(具有调用运算符的对象)的语法糖。
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__{};
}
lambda表达式构造一个闭包对象。这个对象有一个operator()
。我们可以获取呼叫运营商的地址并推断其签名。然后我们只需要std::decay_t
参数类型来删除引用和const-ness。
lambdas的另一个巧妙的技巧是将它们转换为函数指针(我在第一个例子中展示过)。非捕获lambda可以隐式转换为函数指针。您可以使用一元+
或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;
}
如果你不需要捕获lambdas并且可以容忍一元+
那么你可以使用mod_comp
的函数指针重载但是为此,你可能想要捕获lambdas。
抱歉,但是......考虑到您明确调用C...
的变量mod_comp()
类型列表...如何将lambda简单地作为可执行文件传递,忽略与C...
列表的连接?
我的意思是......如下所示(警告:代码未经测试)
template <typename ... C, typename F>
void mod_comp (Entity ent, F && f)
{ return std::forward<F>(f)(get_comp<C>(ent)...); }
这应该只是解决你的主要问题,允许你传递一个lambda(或一个不同的callable),其签名不完全对应C...
,所以也有一些auto &
参数。
以上是关于使用lambda修改由packed参数标识的引用?的主要内容,如果未能解决你的问题,请参考以下文章