以Lambda为模板参数的类如何在其他类中定义成员变量
以Lambda为模板参数的类如何在其他类中定义成员变量
我太懂这种嵌入式开发里的纠结了——既要追求轻量避开std::function的臃肿开销,又想优雅地用lambda实现逻辑,不想写一堆冗余的仿结构体代码。结合你遇到的问题,我给你几个适配不同场景的可行方案:
一、如果编译器支持C++17及以上:用CTAD+类内auto一步解决
C++17带来的两个特性刚好戳中你的痛点:类模板参数自动推导(CTAD)和允许非静态成员用auto做类内初始化。直接这么写就行,简洁又完全没有额外开销:
class A{ int v; // 靠auto推导类型,编译器自动识别lambda的匿名类型 auto a = ActionItem{[this](){ doSomething(v); }}; };
甚至连auto都可以省,直接靠CTAD让编译器推导ActionItem的模板参数:
class A{ int v; // C++17支持类模板参数自动推导,不用手动写ActionItem<具体类型> ActionItem a{[this](){ doSomething(v); }}; };
这种写法完全符合你的需求,既不用写冗余的仿结构体,又避开了std::function的异常处理代码占用Flash的问题。
二、如果只能用C++14或更早版本:用decltype推导lambda类型
C++17之前不支持类模板参数推导,也不让非静态成员用auto,那我们可以用decltype捕获lambda的匿名类型,再显式传给ActionItem做模板参数:
class A{ int v; // 先通过decltype推导lambda的类型,再定义成员变量 decltype(ActionItem{[](int& val){ doSomething(val); }}) a; public: A() : a{[this](){ doSomething(v); }} {} };
要注意,如果你直接在类成员声明里写decltype([this](){...}),有些老编译器可能会报错——因为类还没完全定义,this的作用域会有争议。这时候可以把lambda改成捕获成员变量的引用,绕开this的问题。
三、优化你原来的仿结构体方案:让代码更紧凑
要是你的编译器版本特别老,连C++14都不支持,那只能回到自定义仿函数的路子,但我们可以把代码写得更优雅:
class A{ int v; // 把仿结构体嵌套在A类里,直接捕获当前对象的引用 struct DoSmth{ A& self; void operator()(){ self.doSomething(self.v); } }; // 初始化时直接传当前对象 ActionItem<DoSmth> a{DoSmth{*this}}; };
或者更直接,只捕获需要的成员变量引用:
class A{ int v; struct DoSmth{ int& val; void operator()(){ doSomething(val); } }; ActionItem<DoSmth> a{DoSmth{v}}; };
这种写法和你原来的思路一致,但代码更简洁,而且完全保持轻量,适合资源紧张的嵌入式设备。
为什么你原来的写法会失败?
- 直接写
ActionItem a{[this](){...}}:C++17之前编译器不支持类模板参数自动推导,没法从lambda推导出ActionItem的模板参数Action_F。 - 用
auto a = ActionItem{...}做非静态成员:C++17之前不允许非静态成员变量用auto类型,编译器会直接报错。
内容来源于stack exchange
相关产品推荐
相关产品推荐

