ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c – 使用lambda修改由packed参数标识的引用?

2019-08-23 10:08:20  阅读:200  来源: 互联网

标签:c lambda variadic-templates c17 generic-lambda


我正在尝试在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(速度,位置)与lambda(速度,位置)中的参数匹配.我无法解决这个问题.

然而,主要的问题是如果lambda参数可以简化为像这样的单个mod函数([](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,lambda,variadic-templates,c17,generic-lambda
来源: https://codeday.me/bug/20190823/1696922.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有