C++ Lambda 表达式: 简洁与高效的完美结合

在现代 C++ 开发中, Lambda 表达式以其匿名性和灵活性深受开发者喜爱. 从排序和筛选到高阶函数和泛型支持, Lambda 几乎适用于每一个需要函数对象的场景. 本文将详细介绍 Lambda 的核心概念, 并通过多个实用例子展现其强大功能.


1. 什么是 Lambda 表达式?

Lambda 表达式是 C++ 提供的一种匿名函数形式, 可以在代码中定义并直接使用. 它让代码更加紧凑, 无需额外定义函数, 从而提升开发效率.

基本语法如下:

[捕获列表](参数列表) -> 返回类型 {
    // 函数体
};

2. Lambda 表达式的实际用法

排序操作

在排序操作中, Lambda 可以直接作为 std::sort 的比较函数, 让代码更加简洁. 例如:

#include <algorithm>
#include <iostream>
#include <ranges>
#include <string>
#include <vector>

struct Record {
  std::string primary;
  std::string secondary;
};

bool LessRecord(const Record& p1, const Record& p2) {
  return p1.primary < p2.primary ||
         (p1.primary == p2.primary && p1.secondary < p2.secondary);
}

int main() {
  std::vector<Record> records = {{"A", "1"}, {"B", "0"}, {"a", "2"}};
  // before
  std::sort(records.begin(), records.end(), LessRecord);

  // after
  std::sort(records.begin(), records.end(),
            [](const Record& p1, const Record& p2) {
              return p1.primary < p2.primary ||
                     (p1.primary == p2.primary && p1.secondary < p2.secondary);
            });

  // also support ranges
  std::ranges::sort(records, [](const Record& p1, const Record& p2) {
    return p1.primary < p2.primary ||
           (p1.primary == p2.primary && p1.secondary < p2.secondary);
  });

  for (const auto& record : records) {
    std::cout << record.primary << " " << record.secondary << std::endl;
  }
  return 0;
}

输出:

A 1
B 0
a 2

配合标准算法库使用

除了sort, 在标准算法库的中, 通过 Lambda 表达式可以省去额外定义工具函数, 就地解决:

#include <algorithm>
#include <iostream>
#include <ranges>
#include <string>
#include <vector>

struct Record {
  std::string primary;
  std::string secondary;
};

int main() {
  std::vector<Record> records = {{"A", "1"}, {"B", "0"}, {"a", "2"}};

  // also support ranges
  std::ranges::sort(records, [](const Record& p1, const Record& p2) {
    auto toLower = [](char c) { return std::tolower(c); };
    return std::ranges::lexicographical_compare(p1.primary, p2.primary,
                                                std::less{}, toLower, toLower);
  });

  for (const auto& record : records) {
    std::cout << record.primary << " " << record.secondary << std::endl;
  }
  return 0;
}

输出:

A 1
a 2
B 0

自定义捕获

通过捕获外部变量, Lambda 的灵活性得以提升. 例如, 累加数组元素时使用引用捕获:

#include <algorithm>
#include <iostream>
#include <vector>

int main() {
  std::vector<int> vec{1, 2, 3, 4, 5, 6};

  double sum = 0.0;
  std::for_each(vec.begin(), vec.end(), [&sum](double d) { sum += d; });

  std::cout << "Total: " << sum << '\n';
  return 0;
}

输出:

Total: 21

返回 Lambda 的高阶函数

Lambda 还能作为返回值生成动态函数, 例如:

#include <algorithm>
#include <iostream>
#include <vector>

int main() {
  auto make_interest_func = [](double rate) {
    return [rate](double principal) { return principal * (1 + rate); };
  };

  // 创建一个计算 5% 利息的函数
  auto calculate_interest = make_interest_func(0.05);
  std::cout << "Amount with interest: " << calculate_interest(100) << '\n';
  return 0;
}

输出:

Amount with interest: 105

3. Lambda 的高级特性

mutable 修饰符

如果需要修改按值捕获的变量, 可以使用 mutable 关键字:

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

int main() {
  auto fib = [i = 0, j = 1]() mutable {
    i = std::exchange(j, i + j);
    return i;
  };
  for (int i = 0; i < 10; i++) {
    cout << fib() << ", ";
  }
  return 0;
}

输出

1, 1, 2, 3, 5, 8, 13, 21, 34, 55,

泛型 Lambda

通过 auto 参数, Lambda 可支持多种类型:

#include <iostream>
#include <string>

using namespace std::string_literals;

int main() {
  auto add = [](auto x, auto y) { return x + y; };
  std::cout << add(1, 2) << '\n';      // 输出 3
  std::cout << add(1.5, 2.5) << '\n';  // 输出 4.0
  std::cout << add(std::string("Hello "), "world.") << '\n';    // 输出 HelloWorld
  return 0;
}

输出:

3
4
Hello world.

4. 总结

C++ Lambda 表达式为开发者提供了强大的工具, 从提升代码简洁性到支持高级特性, 极大地优化了开发效率. 无论是简单的排序还是复杂的高阶函数, Lambda 都展现了其灵活性和强大能力. 在实际项目中, 合理利用 Lambda 表达式, 能够显著提升代码质量和开发效率.

希望本文能够帮助你深入理解和掌握 C++ Lambda 表达式的用法. 如果你有任何疑问或想法, 欢迎留言讨论!

源码链接

源码链接

Tags: