C++中的lambda函数(匿名函数)[](){}

前言

本博客大部分抄之《C++标准库》书籍

Lambda

C++11引入了lambda,允许inline函数的定义被用作一个参数,或是一个local对象.

Lambda语法

lambda是一份功能定义,可被定义于语句,表达式内部.

最小型的lambda函数没有参数,如下:

[] {
    std::cout << "hello lambda" << std::endl;
}

也可以直接调用它:

[] {
    std::cout << "hello lambda" << std::endl;
} () //prints "hello lambda"

 或者把它传递给对象,使之能够被调用:

auto l = [] {
    std::cout << "hello lambda" << std::endl;
} () //prints "hello lambda"
...
l(); // prints "hello lambda"

lambda总是由一个lambda introducer引入:那是一组方括号,可以指名一个所谓的capture,用来在lambda内部访问"nonstatic外部对象"。如果无需访问外部数据,这组方括号可以为空,就像本例所示。Static对象,诸如std::count式可被使用的。

在lambda introducer和lambda body之间,可以指明参数或mutable,或一份异常明细(exception specification)或attribute specifier以及返回类型,这些可有可无,但如果其中一个出现了,参数所需小括号就必须出现。因此lambda语法也可以是:

[...] {...}
或
[...] (...) mutable throwSpec -> retType {...}
lambda可以拥有参数,指明于小括号内, 就像任何函数一样:
auto l = [] (const std::string &s) {
    std::cout << s << std::endl;
};
l("hello lambda"); //prints "hello lambda"

Capture(用以访问外部作用域)

在lambda最开始的方括号内,可以指明一个capture用来处理外部作用域内未被传递为实参的数据,意思就是说让lambda内部函数可以访问外部数据:

  • [=] 意味著外部作用域以by value方式传递给lambda。因此当这个lambda被定义时,你可以读取所有外部可读数据(readable data),但是不能改动他们
  • [&] 意味着外部作用域以by reference 方式传递给lambda。因此当这个lambda被定义时,你对所有数据的涂写动作都合法,前提是你拥有涂写他们的权力。

也可以个别指明lambda之内所访问的每个对象是by value或者by reference,可以混合不同访问权力,例如:

int x=0;
int y=42;
auto qqq = [x, &y] {
    std::cout << "x: " << x << std::endl;
    std::cout << "y: " << y << std::endl;
    ++y; //OK
}

x = y = 77;
qqq();
qqq();
std::cout << "final y:" << y << std::endl;

会产生如下输出:

扫描二维码关注公众号,回复: 17134067 查看本文章
x: 0
y: 77
x: 0
y: 78
final y:=79

由于x是by value获得一份拷贝,可以在lambda改动它,但是调用++x是通不过编译的,y是by reference,可以改动,其值变化会改变外部,也可以写[=,&y] 取代 [x,&y],其他所有实参通过by value,y是by reference.

为了获得passing by value和passing by reference混合体,可以声明lambda为mutable。

下例中,对象都是by value方式传递,但是在lambda所定义的函数对象内,有权利改变写传入的值

int id = 0;
auto f = [id] () mutable {
    std::cout << "id: " << id << std::endl;
    ++id; // OK
};

id = 42;
f();
f();
f();
std::cout << id << std::endl

输出如下:

id: 0
id: 1
id: 2
42

可以把上面lambda行为视为下面这个function object

Class {
    private:
        int id;
    public:
        void operator() () {
            std::cout << "id: " << id << std::endl;
            ++id; //OK
    }
};

由于mutable原因,operator()被定义为一个non-const成员函数,意味着对id改写成为可能,由了mutable,lambda变得stateful,即使state是以by value方式传递,如果没有指明mutable,operator()就变成一个const 成员函数,对象就只能读取,因为他们是by value方式传递。

Lambda的类型

lambda类型是不具名function object,每个lambda表达式的类型都是独一无二的,想根据该类型声明对象可以借助template或auto,实在需要写下该类型,可以使用decltype(),例如把一个lambda作为hash function或者ordering准则或sorting准则传递给associative(关联式)容器或unordered(不定序)容器,也可以使用C++标准库提供的std::function<>class template, 指明一个一般化类型给functional programming

如下面例子:

#include<functional>
#include<iostream>

std::function<int(int,int)> returenlambda ()
{
   return [] (int x, int y) {
        return x*y;
    };

}

int main()
{
    auto lf = returnLambda();
    std::cout << lf(6,7) << std::endl;

  
}

输出:42

参考文献:

《C++标准库》

猜你喜欢

转载自blog.csdn.net/u012895183/article/details/134939071