C++ 匿名函数(lambda表达式)

梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)


  本教程将从 C++ 匿名函数(lambda表达式)的核心概念、语法结构、使用规则到典型应用场景,全面拆解 lambda 表达式的核心用法,帮助你掌握这一现代 C++ 中高效且灵活的编程工具。

教程目录导航

一、匿名函数(lambda表达式)核心概述

1.1 基本定义

C++11 引入的lambda表达式(也称为匿名函数)是一种无需命名的内联函数,它允许在代码中直接定义短小的函数片段,可捕获上下文中的变量,是现代 C++ 中实现“函数式编程”和简化代码的核心特性。

lambda表达式本质是一个闭包(Closure)——能捕获并访问其所在作用域中变量的函数对象,编译器会自动将lambda表达式转换为一个匿名的类(仿函数),该类重载了 operator() 运算符。

1.2 lambda表达式的核心特性

特性 说明
匿名性 无需定义函数名,可直接在使用处内联定义,减少命名冗余
捕获性 可捕获所在作用域的变量(值捕获、引用捕获、混合捕获等)
内联性 编译器可直接内联优化,性能优于普通函数调用
灵活性 支持参数、返回值、可变捕获,可作为参数传递给STL算法
临时性 通常用于临时的、短小的函数逻辑,用完即弃,无需复用

1.3 lambda表达式的优势

相比传统的函数/函数指针/仿函数,lambda表达式具有以下核心优势:

二、lambda表达式的语法与基本使用

2.1 核心语法结构

lambda表达式的完整语法格式如下(部分可选):


// 完整语法
[capture-list] (parameter-list) mutable noexcept -> return-type {
    // 函数体(lambda的执行逻辑)
}

// 简化形式(常用)
[capture-list] (parameter-list) { 函数体 }          // 无返回值/返回值自动推导
[capture-list] { 函数体 }                          // 无参数、无返回值
        

各部分说明:

基础示例:最简lambda表达式


#include 
using namespace std;

int main() {
    // 无捕获、无参数、无返回值的lambda
    auto printHello = []() {
        cout << "Hello, Lambda!" << endl;
    };
    
    // 调用lambda表达式(类似函数调用)
    printHello();
    
    // 直接调用(匿名使用,无需赋值给变量)
    []() {
        cout << "匿名调用Lambda!" << endl;
    }();
    
    return 0;
}
        

输出结果:

Hello, Lambda!
匿名调用Lambda!
        

2.2 捕获列表(Lambda的核心)

捕获列表用于指定lambda表达式可访问的外部变量,核心捕获方式如下:

捕获方式 语法 说明
空捕获 [] 不捕获任何外部变量
值捕获 [var] / [=] [var]:捕获变量var(值传递);[=]:捕获所有外部变量(值传递)
引用捕获 [&var] / [&] [&var]:捕获变量var(引用传递);[&]:捕获所有外部变量(引用传递)
混合捕获 [=, &var] / [&, var] 部分变量值捕获,部分变量引用捕获
this捕获(类中) [this] 捕获当前类的this指针,可访问类的成员变量/函数

示例:不同捕获方式的使用


#include <iostream>
using namespace std;

int main() {
    int a = 10, b = 20;
    
    // 1. 值捕获:捕获a(值传递),lambda内修改不影响外部
    auto lambda1 = [a]() mutable {
        a += 5;  // 需加mutable才能修改值捕获的变量
        cout << "lambda1内a = " << a << endl;  // 输出:15
    };
    lambda1();
    cout << "外部a = " << a << endl;  // 输出:10(值捕获不影响外部)
    
    // 2. 引用捕获:捕获b(引用传递),lambda内修改影响外部
    auto lambda2 = [&b]() {
        b += 5;
        cout << "lambda2内b = " << b << endl;  // 输出:25
    };
    lambda2();
    cout << "外部b = " << b << endl;  // 输出:25(引用捕获影响外部)
    
    // 3. 混合捕获:a值捕获,b引用捕获
    auto lambda3 = [a, &b]() mutable {
        a += 10;
        b += 10;
        cout << "lambda3内a = " << a << ", b = " << b << endl;  // 20, 35
    };
    lambda3();
    cout << "外部a = " << a << ", b = " << b << endl;  // 10, 35
    
    // 4. 捕获所有变量:[=]值捕获所有,[&]引用捕获所有
    auto lambda4 = [=]() {
        cout << "lambda4内a = " << a << ", b = " << b << endl;  // 10, 35
    };
    auto lambda5 = [&]() {
        a += 5;
        b += 5;
        cout << "lambda5内a = " << a << ", b = " << b << endl;  // 15, 40
    };
    lambda4();
    lambda5();
    cout << "外部a = " << a << ", b = " << b << endl;  // 15, 40
    
    return 0;
}
        

2.3 返回值类型推导

lambda表达式的返回值类型可省略,编译器会自动推导;若函数体包含多个return语句且类型不同,需显式指定返回值类型:


#include <iostream>
using namespace std;

int main() {
    // 自动推导返回值(int)
    auto add = [](int x, int y) {
        return x + y;
    };
    cout << "3 + 5 = " << add(3, 5) << endl;  // 输出:8
    
    // 显式指定返回值类型(解决多return类型不一致问题)
    auto calculate = [](int x, int y) -> double {
        if (y != 0) {
            return (double)x / y;  // double类型
        } else {
            return 0;  // int类型,需显式指定返回值为double
        }
    };
    cout << "10 / 3 = " << calculate(10, 3) << endl;  // 输出:3.33333
    
    return 0;
}
        

2.4 参数列表与通用lambda(C++14)

C++14 支持通用lambda,使用auto作为参数类型,实现类似模板的效果:


#include <iostream>
#include <string>
using namespace std;

int main() {
    // 通用lambda:参数类型自动推导
    auto printAny = [](auto val) {
        cout << "值:" << val << endl;
    };
    
    printAny(100);                // 输出:值:100
    printAny(3.14);               // 输出:值:3.14
    printAny("Hello Lambda");     // 输出:值:Hello Lambda
    printAny(string("C++14"));    // 输出:值:C++14
    
    // 带默认参数的lambda(C++14)
    auto addWithDefault = [](int x, int y = 10) {
        return x + y;
    };
    cout << "5 + 默认值 = " << addWithDefault(5) << endl;  // 输出:15
    cout << "5 + 8 = " << addWithDefault(5, 8) << endl;    // 输出:13
    
    return 0;
}
        

三、lambda表达式的进阶特性

3.1 mutable关键字:修改捕获变量

值捕获的变量默认是const的,无法修改;添加mutable关键字后,允许在lambda内部修改值捕获的变量(仅影响内部副本,不影响外部):


#include <iostream>
using namespace std;

int main() {
    int num = 10;
    
    // 错误:值捕获的num默认const,无法修改
    // auto lambdaErr = [num]() {
    //     num += 5;  // 编译报错
    // };
    
    // 正确:加mutable允许修改内部副本
    auto lambdaMutable = [num]() mutable {
        num += 5;
        cout << "lambda内num = " << num << endl;  // 输出:15
    };
    lambdaMutable();
    cout << "外部num = " << num << endl;  // 输出:10(内部修改不影响外部)
    
    return 0;
}
        

3.2 闭包与lambda的本质

lambda表达式的本质是编译器自动生成的匿名仿函数类,lambda的调用等价于调用该类的operator()方法:


#include <iostream>
using namespace std;

// lambda表达式等价的仿函数实现
class LambdaEquivalent {
private:
    int a;  // 对应值捕获的变量
    int& b; // 对应引用捕获的变量
public:
    // 构造函数:接收捕获的变量
    LambdaEquivalent(int a_, int& b_) : a(a_), b(b_) {}
    
    // 重载operator()(mutable对应函数非const)
    void operator()() mutable {
        a += 5;
        b += 5;
        cout << "仿函数内a = " << a << ", b = " << b << endl;
    }
};

int main() {
    int a = 10, b = 20;
    
    // lambda表达式
    auto lambda = [a, &b]() mutable {
        a += 5;
        b += 5;
        cout << "lambda内a = " << a << ", b = " << b << endl;
    };
    lambda();  // 输出:lambda内a = 15, b = 25
    
    // 等价的仿函数调用
    LambdaEquivalent func(a, b);
    func();    // 输出:仿函数内a = 15, b = 30
    
    return 0;
}
        

3.3 lambda作为函数参数/返回值

lambda可作为函数参数(需配合std::function)或返回值,实现灵活的回调函数:


#include <iostream>
#include <functional>  // 包含std::function
using namespace std;

// 1. lambda作为函数参数(使用std::function)
void processData(int data, function<int(int)> handler) {
    int result = handler(data);
    cout << "处理后结果:" << result << endl;
}

// 2. lambda作为返回值
function<int(int)> getMultiplier(int factor) {
    // 返回捕获factor的lambda
    return [factor](int x) {
        return x * factor;
    };
}

int main() {
    // 传递lambda作为参数
    processData(10, [](int x) {
        return x * 2;  // 处理逻辑:乘以2
    });  // 输出:处理后结果:20
    
    // 获取返回的lambda
    auto multiplyBy3 = getMultiplier(3);
    cout << "5 * 3 = " << multiplyBy3(5) << endl;  // 输出:15
    
    auto multiplyBy5 = getMultiplier(5);
    cout << "5 * 5 = " << multiplyBy5(5) << endl;  // 输出:25
    
    return 0;
}
        

3.4 lambda与STL容器/算法结合

lambda是STL算法的最佳搭档,可简化排序、遍历、查找等操作:


#include <iostream>
#include <vector>
#include <algorithm>  // 包含STL算法
using namespace std;

int main() {
    vector<int> nums = {5, 2, 9, 1, 5, 6};
    
    // 1. 排序:按降序排列(替代自定义比较函数)
    sort(nums.begin(), nums.end(), [](int a, int b) {
        return a > b;
    });
    cout << "降序排序结果:";
    for (int num : nums) cout << num << " ";  // 输出:9 6 5 5 2 1
    cout << endl;
    
    // 2. 遍历:打印所有元素(替代for循环)
    cout << "遍历容器:";
    for_each(nums.begin(), nums.end(), [](int num) {
        cout << num << " ";
    });  // 输出:9 6 5 5 2 1
    cout << endl;
    
    // 3. 查找:查找第一个大于5的元素
    auto it = find_if(nums.begin(), nums.end(), [](int num) {
        return num > 5;
    });
    if (it != nums.end()) {
        cout << "第一个大于5的元素:" << *it << endl;  // 输出:9
    }
    
    // 4. 计数:统计等于5的元素个数
    int count5 = count_if(nums.begin(), nums.end(), [](int num) {
        return num == 5;
    });
    cout << "等于5的元素个数:" << count5 << endl;  // 输出:2
    
    return 0;
}
        

四、lambda表达式的典型应用场景

五、注意事项

六、总结

本教程从lambda表达式的核心概念、语法结构、进阶特性到典型应用场景,全面拆解了C++匿名函数的使用方法。掌握lambda表达式,能显著提升现代C++编程的效率和代码质量,是C++进阶学习的重要知识点。


返回顶部