C++11 lambda表达式用法

Lambda表达式(匿名函数、Lambda函数)是现代C++在C ++ 11和更高版本中的一个新的语法糖,可以让我们快速便捷的创建一个函数。

[ capture-list ] ( params ) mutable exception attribute -> return-type { body }

capture-list:捕获列表,一般在Lambda表达式开头,捕获上下文中的变量,用逗号分隔。

params:参数列表,函数所需参数,写法同函数参数,但是不支持默认参数。若没有参数可连同"()"直接省略。

mutable:可变规格(修饰符),当捕获列表是以复制的形式捕获时,默认复制值为const,若指定mutable则可取消其常量性。

exception:异常说明,用于函数内部抛出异常。

attribute:声明属性。

return-type:返回值类型,可省略。

body:函数体。

捕获列表说明:lambda表达式的捕获列表精细控制了lambda表达式能够访问的外部变量,以及如何访问这些变量。

1).[]不捕获任何变量。

2).[&]以引用的方式捕获所有变量。

3).[=]以拷贝的方式捕获所有变量。

4).[=,&foo]按值捕获外部作用域中所有变量,并按引用捕获foo变量。

5).[var]表示值传递方式捕获变量var。

6).[this]捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限。如果已经使用了&或者=,就默认添加此选项。捕获this的目的是可以在lamda中使用当前类的成员函数和成员变量。

auto lambda_test = [] {std::cout << "Hello, World!\n";};
lambda_test();

上例将打印字符的lambda函数赋给了lambda_test,然后直接调用函数。运行可得到结果"Hello,World!"

Lambda应用场景:当我们需要使用一次性函数时我们可以直接使用lambda函数,避免工程文件定义过多的非常用函数。

 


 

需注意,lambda表达式无法捕捉局部静态变量,如下例:

vector<function<void()>>fd;

void func() {
    static int a = 1;
    auto f = []() {
        cout << a << endl;
    };
    fd.emplace_back(f);
    a++;
}

int main()
{
    func();
    func();
    func();
    func();
    fd[0]();
    fd[1]();
    fd[2]();
    fd[3]();
    return 0;
}

vs2022输出如下

 可以看到lambda未捕获任何值或引用,但是依然可用使用局部静态变量a,本人推测局部静态变量可被同作用域下的lambda默认引用捕获,即与下面情况相同

void func() {
    static int a = 1;
    auto f = [&p=a]() {
        cout << p << endl;
    };
    fd.emplace_back(f);
    a++;
}

括号内的内容可理解为 auto& p=a,p为a的引用。

及时上述lambda修改为[=]默认按值捕获,也不会按值捕获a的值,而是依然为引用捕获,即输出仍为全5,除非将lambda修改为如下:

void func() {
    static int a = 1;
    auto f = [p=a]() {
        cout << p << endl;
    };
    fd.emplace_back(f);
    a++;
}

 需注意,lambda的初始化捕获(即上文中的[p=a] [&p=a])是c++14才有的,c++11中可以使用闭包类来代替lambda实现,例子如下:

//c++14
class Widget {                          //一些有用的类型
public:
    …
    bool isValidated() const;
    bool isProcessed() const;
    bool isArchived() const;
private:
    …
};

auto pw = std::make_unique<Widget>();   //创建Widget;使用std::make_unique
//设置*pw

auto func = [pw = std::move(pw)]        //使用std::move(pw)初始化闭包数据成员
            { return pw->isValidated()
                     && pw->isArchived(); };
//c++11
class IsValAndArch {                            //“is validated and archived”
public:
    using DataType = std::unique_ptr<Widget>;
    
    explicit IsValAndArch(DataType&& ptr)       
    : pw(std::move(ptr)) {}
    
    bool operator()() const
    { return pw->isValidated() && pw->isArchived(); }
    
private:
    DataType pw;
};

auto func = IsValAndArch(std::make_unique<Widget>());

 这块有关的更详细的内容请查阅EffectiveModernCpp 条款32

 

参考文章:

https://paul.pub/cpp-lambda-function-bind/

https://blog.csdn.net/qq_37085158/article/details/124626913?spm=1001.2014.3001.5506

posted @ 2023-03-30 20:34  _Explosion!  阅读(80)  评论(0编辑  收藏  举报