# C++ lambda表达式教程

C++11引入了lambda表达式，而之后的语言版本不断的对lambda表达式进行改善。lambda表达式表示一个匿名函数。如今，lambda表达式已成为C++语言的核心组成部分，而这篇博文就是给还不了解lambda表达式的C++程序员讲解它的使用方法以及原理。

## 基本用法

#include <algorithm>
#include <cmath>

void abssort(float* x, unsigned n) {
std::sort(x, x + n,
[](double a, double b) {
return (std::abs(a) < std::abs(b));
});
}

#include <algorithm>
#include <cmath>

bool abs_less(double a, double b) {
return (std::abs(a) < std::abs(b));
}

void abssort(float* x, unsigned n) {
std::sort(x, x + n, abs_less);
}

## 捕获 (capture)

// Get a new vector<int> with element above a certain number in the old vector
std::vector<int> filter_above(const std::vector<int>& v, int threshold) {
std::vector<int> result;
std::copy_if(
std::begin(v), std::end(v),
std::back_insert_iterator(result),
[threshold](int x){return x > threshold;});
return result;
}

// filter_above(std::vector<int>{0, 1, 2, 4, 8, 16, 32}, 5) == std::vector<int>{8, 16, 32}

auto greeter() {
std::string name{"Lesley"};

return std::async([&](){
std::cout << "Hello " << name << '\n';
});
}

## Lambda的原理

### 函数对象 (Function Object)

#include <algorithm>
#include <cmath>
class abs_less {
bool operator()(double a, double b) {
return (std::abs(a) < std::abs(b));
}
};

void abssort(float* x, unsigned n) {
std::sort(x, x + n, abs_less{});
}

template <typename T>
class GreaterThan {
public:
GreaterThan(T threshold): threshold_{threshold} {
}

bool operator()(const T& other) noexcept {
return other > threshold_;
}

private:
T threshold_;
};

std::vector<int> filter_above(const std::vector<int>& v, int threshold) {
std::vector<int> result;
std::copy_if(std::begin(v), std::end(v), std::back_insert_iterator(result), GreaterThan{threshold});
return result;
}

### 从函数对象到lambda表达式

#include <algorithm>
#include <cmath>

void abssort(float * x, unsigned int n)
{

class __lambda_6_9
{
public: inline /*constexpr */ bool operator()(float a, float b) const
{
return (std::abs(a) < std::abs(b));
}

...
};

std::sort(x, x + n, __lambda_6_9{});
}

C++编译器会生成lambda表达式的类型，但是这些类型的名字是不会暴露给程序员的。尽管如此，对于这些类型，类型推论（type inference）以及模板仍然工作如常。我们也可以通过decltype来直接使用这些类型。如下是一个在cppreference上的例子：

auto f = [](int a, int b) -> int
{
return a * b;
};

decltype(f) g = f;

## 带有初始化器的捕获符

[x = 1]{ return x; // 1 }

### 捕获仅可移动的类型

Rust语言的lambdas表达式可以夺取被捕获对象的所有权（ownership）。C++ lambda对这种“移动捕获”没有特殊的支持，但是C++14中的通用捕获可以用来实现这种功能：

// unique_ptr是move only的类型
auto u = make_unique<some_type>(
some, parameters
);
// 将unique_ptr的所有权移入lambda
go.run([u=move(u)] {
do_something_with( u );
});

## 立即调用lambda (Immediately Invoked Lambda)

[]() { std::puts("Hello world!"); }();

std::vector<std::string> lines;
for (std::string line;
std::getline(std::cin, line);) {
lines.push_back(line);
}

const auto lines = []{
std::vector<std::string> lines;
for (std::string line;
std::getline(std::cin, line);) {
lines.push_back(line);
}
return lines;
}();