码迷,mamicode.com
首页 > 编程语言 > 详细

C++中lambda的实质是什么?

时间:2015-04-27 21:57:47      阅读:407      评论:0      收藏:0      [点我收藏+]

标签:lambda   c++   

我们知道lambda表达式的行为很像是是一个匿名函数,我们常常在标准算法中使用lambda表达式。比如需要打印一个向量,可能会这样写:

vector<int> v(10, 10);

std::for_each(v.begin(), v.end(), [](int n){
    cout << n << " ";
});

使用了for_each算法针对 v 中的每一个元素使用lambda表达式,并且成功的达到了目的。

但是看看下面这个方式也可以完成任务:

std::for_each(v.begin(), v.end(), print_int);

这里的print_int 是什么呢?多数人都会知道它是一个形如void print_int(int)的函数,没错,但是他还可以是另外一类截然不同的类型,也就是说它并不是一个函数。

在学习类的运算符重载的时候,很多人可能会忽略掉()的重载,也就是括号的重载。我们知道对类的括号进行重载就能想函数一样使用类对象。举例如下:

class Print{
    void operator()(int n){
        cout << n << " ";
    }
};

Print print_int;  //声明类对象
print_int(3);     //使用了()运算符

这样我们将3打印出来了。所以上面for_each语句中的print_int也可以是一个类对象。说这些的目的只是为了引出下面的话题,那就是lambda表达式的本质是什么?

其实在C++中,lambda表达式都被编译器翻译成了一个未命名的类的一个未命名对象。上面的lambda表达式,就被翻译成了形如Print类的一个未命名类,而在for_each中,声明了一个未命名的对象,然后使用其括号运输符来完成 v 中各个元素的处理。

我们知道,lambda表达式前面的 [] 是捕获列表,而捕获方式有通过引用捕获和通过值捕获。当通过值引用的时候,编译器在创建类的时候,会将这个值作为类成员变量,而在声明未命名对象的时候,将这个类成员初始化为所引用的变量当前的值。

当通过引用的方式捕获时,编译器不会将其存储为类成员。下面通过一个例子来说明以上内容。

int value = 100;
auto it = find_if(v.begin(),v.end(),[value](const int n){
    return n<value;
});
cout<<*it;

上面这段代码是为了找到 v 中小于 100 的第一个数,这里我将长度最大长度按值传递给lambda表达式。编译器为之可能产生下面这个类:

class XXX{
public:
    XXX(int x):value(x){}  //这里的x就是捕获列表中的变量 --- [value]
    bool operator()(const int n)const{  //这里与lambda的参数,返回值,函数体一致
        return n<value;
    }
private:
    int value;
};

之后,我们可以这样做:

int value = 100;

XXX xx(value);
auto it = find_if(v.begin(), v.end(), xx);
cout<<*it;

毫无疑问,这里find_if对v中每一个元素调用了xx.operator(int n),通过返回值得到了指向第一个小于value的值的迭代器。

其实你还可以这样使用XXX类:

auto it = find_if(v.begin(), v.end(), XXX(100));

现在你或许对lambda表达式有有了一些认识,所以不妨自己定义一个这样的类来测试一下,是否真的如我这里所说。

C++中lambda的实质是什么?

标签:lambda   c++   

原文地址:http://blog.csdn.net/wy_ei/article/details/45314321

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!