本文详细介绍下C++11的lambda表达式的语言特性。

lambda表达式总体特点:

  1. Lambda函数作为临时的函数,最常要数用于STL算法了,我们的很多STL算法可以指定一个函数参数,比如:accumulate, for_each, find_if, count_if, search, mismatch, sort等几十个算法函数。C++0x以前我们必须用有名的函数或者函数对象(bind,not等组合)来作为参数,现在无名的Lambda函数直接简单的嵌入到代码中了,方便简洁。
  2. 除了STL算法,当我们需要简单的函数,并且只在作用域出现不多次时,我们就可以直接用auto存储Lambda函数对象,避免使用有名的函数放到外层作用域。
  3. 利用boost的function库,我们可以保存同一类型的多个Lambda的函数对象,放到标准容器中,在局部生成lambda函数也能来实现回调。

语法解析

语法:

[capture-list] ( argument-list ) mutable -> ReturnType { function-body }

C++14 的lambda新语法特征

int x = 4;
auto y = [&r = x, x = x+1]()->int {
    r += 2;
    return x+2;
}();
// x:6, y:7

关于lambda表达式转换C函数类型

当lambda表达式没有使用变量捕获时,可以转换为函数指针,比如:

EXPORT void obs_enum_sources(bool (*enum_proc)(void*, obs_source_t*),
		void *param);

// Usage
obs_enum_sources( [](void* data, obs_source_t* source){
	// ...
	return true;
}, this );

lambda语句返回函数对象的操作

  1. 直接传给STL算法等可以接受函数对象的地方。
  2. 直接可以调用,右边加上括号、参数 ( real-argu-list ),语法和普通函数对象一致。
  3. 由于函数对象对应的类不是从标准库的unary_function, binary_function继承,所以无法使用bind1st, not1等绑定器。但是我们有更加强大的auto或者boost的bind和function库,分别可以用来部分绑定和存储返回的函数对象

代码示例

lambda函数的常用于算法和auto临时存储

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <iterator>
#include <boost/bind.hpp>
using namespace std;

struct BasicInfo
{
	BasicInfo( const string& name, int age ) 
		: name_(name), age_(age) {}
	string name_;
	int age_;
};

int main()
{
	vector< BasicInfo > vect;
	vect.push_back( BasicInfo("tom", 15) );
	vect.push_back( BasicInfo("Jam", 18) );
	vect.push_back( BasicInfo("Yea", 15) );	
	vect.push_back( BasicInfo("Jack", 59) );
	vect.push_back( BasicInfo("Master", 35) );

	vector<string> NamesVect(vect.size());
	int idx=0;
	for_each( NamesVect.begin(), NamesVect.end(), [&]( string& s ){ s = vect[idx++].name_; } );
	
	for_each( NamesVect.begin(), NamesVect.end(), [](const string& s){ cout << s+" "; } );
	cout << endl << "idx = " << idx << endl;

	//---------------------------------------
	idx = 0;
	vector<int> intVect;
	generate_n( back_inserter(intVect), 10, [&idx]() { return idx++; } );
	generate_n( back_inserter(intVect), 10, [&idx]() { return --idx; } );
	// 0 1 2 3 4 5 6 7 8 9 9 8 7 6 5 4 3 2 1 0
	copy( intVect.begin(), intVect.end(), 
	    ostream_iterator<int>( cout, " " ) );
	cout << endl;

	auto func = []( int n, int val ) { return val==n; };
	vector<int>::iterator pos = find_if( intVect.begin(), intVect.end(), 
		boost::bind<bool>( func, _1, 3 ) ); // 查找第一个等于3
	if( pos != intVect.end() )
	{
		cout << *pos << endl;
		cout << "index = " << pos - intVect.begin() << endl;
	}
	++pos;
	// 查找第一个3之后不等于4
	pos = find_if( pos, intVect.end(), 
		[&func](int n){ return ! boost::bind<bool>( func,_1,4 )(n); } ); 
	if( pos != intVect.end() )
	{
		cout << *pos << endl;
		cout << "index = " << pos - intVect.begin() << endl;
	}

	return 0;
}

// 输出
// tom Jam Yea Jack Master 
// idx = 5
// 0 1 2 3 4 5 6 7 8 9 9 8 7 6 5 4 3 2 1 0 
// 3
// index = 3
// 5
// index = 5

使用boost的bind和function库来操作lambda函数返回的函数对象,存储到容器

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <utility>
#include <boost/function.hpp>
#include <boost/bind.hpp>
using namespace std;

template< class T >
void Print( const T& v )
{
	typedef typename T::const_reference CValRef;
	for_each( v.begin(), v.end(), 
	    [](CValRef val){ cout << val << " "; } );
	cout << endl;
}

int main()
{
	boost::function< int(int, int) > fun = 
	    [](int x, int y){ return x*y; };
	cout << fun(3,4) << endl; // 12
	cout << 
	    boost::bind<int>([](int x, int y){return x+y;}, 5, _1)(6) 
	    << endl; // 11

	vector<int> vect;
	vect.push_back( 3 );
	vect.push_back( 5 );
	vect.push_back( 2 );	
	vect.push_back( 7 );
	vect.push_back( 3 );
	vect.push_back( 1 );

	boost::function< bool(int,int) > f = 
	    [](int x, int y) { return x<y; };
	
	sort( vect.begin(), vect.end(), f );
	Print(vect); //1 2 3 3 5 7

	sort( vect.begin(), vect.end(), boost::bind<bool>(f,_2,_1) );
	Print(vect); //7 5 3 3 2 1

	//----------------------------------
	vector<int> intTest;
	int val = 0;
	generate_n( back_inserter( intTest ), 10, 
	    [&val](){ return ++val; } );
	Print( intTest );
	vector< function<void(int&)> > funcVect;
	funcVect.push_back( [](int n){ cout << n+2<< endl; } );
	funcVect.push_back( [](int& n){
	    n = 1000; 
	    cout << n << endl; 
	});
	funcVect.push_back( [](int n){ cout << "yes" << endl; } );

	vector<int>::iterator pos = intTest.begin();
	advance( pos, 3 );
	int idx = 0;
	for_each( intTest.begin(), pos, [&]( int& n ) { 
	    return funcVect[idx++]( n ); 
	});
	Print( intTest );

	return 0;
}