如何用Lambda或函数对象实现顺序处理并解决前置引用问题?
解决类方法中Lambda互相调用的编译问题
问题描述
以下是无法编译的最小可复现示例代码,问题在于类方法calculate中,lambda1调用lambda2时lambda2尚未定义,lambda2调用lambda3时lambda3也尚未定义,导致编译错误。尝试用函数对象替换Lambda后仍出现相同问题,需要找到可行的解决方案。
#include<iostream> class sample{ sample()=default; ~sample=default; sample(const sample&)=delete; sample operator=(const sample&)=delete; int calculate (int); }; int sample::calculate(int n){ auto lambda1 = [&](int n)->void{ //do some processing lambda2(); }; auto lambda2 = [&]()->void{ //do some processing lambda3(); }; auto lambda3 = [&]()->void{ //do some processing }; //return result } int main(){ sample s; int n = <some integer value>; auto result = s.calculate(n); std::cout << result << std::endl; return 0; }
解决方案
方法一:使用std::function前置声明
Lambda是匿名类型,无法直接前置声明,但可以用std::function先声明函数对象变量,后续再赋值实现逻辑,这样前面的Lambda就能识别到后续的函数对象。同时需要修正原代码中的语法错误:
- 析构函数补全括号:
~sample()=default; - 赋值运算符修正返回类型:
sample& operator=(const sample&)=delete; - 将类的构造函数等改为
public,否则main无法创建实例
修正后的代码:
#include<iostream> #include<functional> class sample{ public: sample()=default; ~sample()=default; sample(const sample&)=delete; sample& operator=(const sample&)=delete; int calculate(int); }; int sample::calculate(int n){ // 前置声明三个函数对象的类型 std::function<void(int)> lambda1; std::function<void()> lambda2; std::function<void()> lambda3; // 从最底层的lambda开始定义 lambda3 = [&]()->void{ // do some processing std::cout << "lambda3 执行" << std::endl; }; lambda2 = [&]()->void{ // do some processing std::cout << "lambda2 执行" << std::endl; lambda3(); }; lambda1 = [&](int n)->void{ // do some processing std::cout << "lambda1 执行,参数n=" << n << std::endl; lambda2(); }; // 调用lambda1 lambda1(n); // 返回示例结果 return n * 2; } int main(){ sample s; int n = 5; auto result = s.calculate(n); std::cout << "计算结果:" << result << std::endl; return 0; }
方法二:使用自定义函数对象(Functor)并前置声明
通过前置声明结构体类型,依次定义每个函数对象结构体,每个结构体可以包含后续的函数对象实例,实现互相调用。
#include<iostream> class sample{ public: sample()=default; ~sample()=default; sample(const sample&)=delete; sample& operator=(const sample&)=delete; int calculate(int); }; int sample::calculate(int n){ // 前置声明函数对象结构体 struct Lambda3; struct Lambda2; struct Lambda1; // 从底层开始定义结构体 struct Lambda3 { sample* self; Lambda3(sample* s) : self(s) {} void operator()() { // do some processing std::cout << "Lambda3 执行" << std::endl; } }; struct Lambda2 { sample* self; Lambda3 lambda3; Lambda2(sample* s) : self(s), lambda3(s) {} void operator()() { // do some processing std::cout << "Lambda2 执行" << std::endl; lambda3(); } }; struct Lambda1 { sample* self; Lambda2 lambda2; Lambda1(sample* s) : self(s), lambda2(s) {} void operator()(int n) { // do some processing std::cout << "Lambda1 执行,参数n=" << n << std::endl; lambda2(); } }; // 创建函数对象实例并调用 Lambda1 lambda1(this); lambda1(n); return n * 2; } int main(){ sample s; int n = 5; auto result = s.calculate(n); std::cout << "计算结果:" << result << std::endl; return 0; }
关键说明
- Lambda的定义顺序必须是从被调用的最底层开始,这样前面的Lambda在调用时,后续的函数对象已经被赋值/实例化
- 原代码中的语法错误是编译不通过的额外原因,必须先修正才能正常运行
内容的提问来源于stack exchange,提问作者Vinod
相关产品推荐
相关产品推荐

