设为首页 加入收藏

TOP

浅谈C++ Lambda 表达式(简称LB)(一)
2015-07-20 17:42:34 来源: 作者: 【 】 浏览:8
Tags:浅谈 Lambda 表达式 简称
无名引用
对于一次性的,带参数表达式,用LB可以节省不必要的class定义和维护,简化程序的设计-维护代价。
?
比如下面的vector处理代码,简洁明了:
?
vector v1(10, 1);
?
int sum = 0;
?
for_each (v1.begin(), v1.end(), [&](int i){ sum += i; });//Line1
?
?
?
否则,我们必须定义一个function类,把如此简单的事情复杂化。用了LB,我们把定义function 类的工作,转交给编译。VC++中,上述LB编译的实现是产生一个隐身类:
?
?
?
class ?_lambda_a01 {
?
? ? int &capture1_;
?
public:
?
? _lambda_a01(int &x): capture1_(x) {} ?//Line2
?
?operator void (int i) { capture1_ += I; }
?
};
?
?
?
在引用时(Line1),它变成:
?
?
?
_lambda_a01 lbd1(sum);
?
for(auto a:v1){
?
? ?ldb1(a);
?
}
?
?
?
读者也许好奇,为什么C++不直接把LB转换成inline expression (inline 表达式),而是要生成一个隐身类呢?这是因为LB的确可以当成“type”变量来用,这样使得LB和其他类有了同等地位。比如:
?
?
?
vector v1(10, 1);
?
int sum = 0;
?
for_each (v1.begin(), v1.end(), [&](int i){ sum += i; });//Line1
?
vector v2(10, 1);
?
int sum2 = 0;
?
for_each (v1.begin(), v1.end(), [&](int i){ sum2 += i; });//Line2
?
?
?
我们如果用上述的方法,Line1和Line2重复代码,是软件工程的大忌。我们可以用下列LB使用模式:
?
有名无型引用
?
?
vector v1(10, 1);
?
vector v2(10, 1);
?
int sum = 0;
?
auto lb = [&](int i){ sum += i; }; ?//Line0
?
?
?
for_each (v1.begin(), v1.end(), lb);//Line1
?
sum = 0; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// Line1.1
?
for_each (v1.begin(), v1.end(), lb});//Line2
?
?
?
在Line0,我们定义了一个有名(lb)无型的LB,可以在Line1和Line2重复使用。
?
?
?
注意的是,
?
1) 每个LB的“定义”都会产生新的“隐身”类,所以尽量用“有名引用”,会减少代码的size,缩小工作集。
?
2) 定义时,LB一次性“俘获”环境变量,所以上面修改后的代码加了Line1.1,以便正确表达应用逻辑。
?
3) 俘获可以是“传值(by value)”也可以是“传引用(by reference)。我们Line0用的是by reference.
?
?
?
有名有型引用
上面两种LB使用模式,是LB应用的主要模式,它直接反映出了LB的优点。另一方面说,既然LB无非是隐身类,我们没有理由不能把它当作普通变量使用。这个模式是一种简化的functor使用模式。我们可以把LB定义成一个std::function,比如上面的auto lb可以定义成:
?
std::function lb; //lb is a function which takes an integer and returns void
?
?
?
注意到用这个定义,使得我们可以推迟给LB变量赋值,甚至一变量赋多址(不同时间)。下面就是一个简单用例:
?
struct MyLambda
?
{
?
? ? ? ?std::function _lbda;//line1
?
? ? ? ?int _extra;
?
};
?
?
?
MyLambda TestLambdaObj(int t)
?
{
?
? ? ? ?MyLambda ret;
?
? ? ? ?if (t == 1)
?
? ? ? ?{
?
? ? ? ? ? ? ?ret._extra = t;
?
? ? ? ? ? ? ?ret._lbda = [=](int x) ?-> int { return t + x; }; //line2
?
? ? ? ? ? ? ?return ret;
?
? ? ? ?}
?
? ? ? ?else
?
? ? ? ?{
?
? ? ? ? ? ? ?ret._extra = t;
?
? ? ? ? ? ? ?ret._lbda = [=](int x) ?-> int { return t * x; };//line3
?
? ? ? ? ? ? ?return ret;
?
? ? ? ?}
?
}
?
?
?
void TestLambdaFun2(int t)
?
{
?
? ? ? ?MyLambda ret = TestLambdaObj(t);
?
? ? ? ?int v = ret._lbda(t); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//line4
?
? ? ? ?printf("v is '%d' for type %d", v, t);
?
}
?
?
?
我们先定义MyLambda数据类,并与其定义了一了function成员_lbda,根据C++ SPEC,他可以由LB转换构造,并且和普通的类变量无甚区别。然后我们可以运行时给它赋值(line2,line3), 当作普通function来使用(line4)。
?
注意的是:
?
function的定义中没有“闭包”的概念,闭包的形成是在LB创建时实现(line2,line3)。
把LB赋值给function变量,必然造成调用时(line4)的间接性(通过函数指针),其性能相当于虚拟函数,也不能inline化,当然比直接调用有所下降。
闭包(closure)是LB的独特附加值
如果你问为什用LB而不用std::function?我的回答是“闭包”。
?
C++用LB来实现闭包,是一个简化繁琐的class初始化的syntax sugar。这一点是std::function所不可替代的。比如说:
?
auto sum = 0;
?
auto step = 2;
?
auto lb = [&](int i){ sum += i + step; }//capture sum and step by ref
?
?
?
lb形成
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇small tree 下一篇poj Monthly Expense(最大值最小..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·MySQL 安装及连接-腾 (2025-12-25 06:20:28)
·MySQL的下载、安装、 (2025-12-25 06:20:26)
·MySQL 中文网:探索 (2025-12-25 06:20:23)
·Shell脚本:Linux Sh (2025-12-25 05:50:11)
·VMware虚拟机安装Lin (2025-12-25 05:50:08)