向左右向右走 —— 小时了了的技术博客

关注C++开发技术、架构设计、软件项目管理、软件产品管理等

posts - 19,comments - 55,trackbacks - 0

  先看一段使用了std::list的代码:

	std::list<int> array;
	for(int i = 0; i < 10; i++)
	{
		array.push_back(i);
	}

	for (std::list<int>::iterator it = array.begin(); it != array.end(); ++it)
	{
		(*it) += 1;
	}

	for (std::list<int>::iterator it = array.begin(); it != array.end(); ++it)
	{
		printf("%d\t", *it);
	}

  我们观察这段代码。首先,它是正确的,没什么错误,但看起来太臃肿了。本来我要完成每个元素的值加1关键的代码只有一行

  (*it) += 1;

  现在却要写上四行,再加一个空行五行。还有,“it”的类型声明也是一个麻烦事,写的长不说还要随时记住类型,修改时也麻烦。总之写得痛苦看着不爽,所以需要优化。

 

  STL中提供了for_each算法,这是首先想到的优化方法,一起来看看效果:

	std::for_each(array.begin(), array.end(), _AutoPlus(1));
	std::for_each(array.begin(), array.end(), _PrintArrayItem());

  还不错是吧,且慢,_AutoPlus和_PrintArrayItem是什么东东?好吧,看定义:

struct _PrintArrayItem
{
	void operator()(int n)
	{
		printf("%d\t", n);		
	}
};

struct _AutoPlus
{
	void operator()(int& n)
	{
		n += nVal;
	}

	_AutoPlus(int n) : nVal(n) {}
	int nVal;
};

 

  原来是两个仿函数,用以封装对list元素的操作。看起来挺酷的,数数代码行吧——晕了,比原来的还多。看来这种方法只适用多个地方重复相同操作的情况,因为只有这种情况下定义仿函数才觉得值。那么怎么办呢?

 

  我为上面这个事情郁闷了很久,直到有一天偶然知道了VS2010已经支持C++ 0x的新特性lambda表达式,不由得心中一喜,赶快试试:

 

	// 用lambda表达式实现累加,注意参数声明是int&
	std::for_each(array.begin(), array.end(), [](int& n) { n++; });
	// 用lambda表达式实现打印输出
	std::for_each(array.begin(), array.end(), [](int n){ printf("%d\t", n); });

  “[]”开头的部分就表示lambda表达式了,真的是个不错的特性,现在代码简洁多了完全达到预期。lambda表达式实质上是生成了一个临时的匿名仿函数对象,不要小看匿名这两个字,有了它我们就不需要提前写麻烦的仿函数声明,代码逻辑也就不会分散到各个角落从而造成理解上的障碍。

 

  对复杂一点的操作我们可能希望先把lambda表达式写好然后当作参数使用,这时候auto关键字就派上用场了。auto关键字用于自动类型推断,我们可以把一个lambda表达式赋值给一个auto型的变量,这样就不必为lambda表达式的类型费心了:

 

	auto _AutoIncr = [](int& n) { n++; };
	auto _PrintItem = [](int n){ printf("%d\t", n); };
	std::for_each(array.begin(), array.end(), _AutoIncr);
	std::for_each(array.begin(), array.end(), _PrintItem);

 

  是不是很酷啊,呵呵。

 

  关于VS2010对C++ 0x新特性的支持可以参考这篇文章:

   【译】VC10中的C++0x特性 part 1:Lambdas,auto,以及 static_assert

posted on 2010-12-04 15:49 小时了了 阅读(...) 评论(...) 编辑 收藏