2011-08-17 142 views
24

我做一个简单的正常化向量(权重),试图利用STL算法使代码尽可能干净(我意识到这是相当琐碎与循环):如何从C++ 11匿名函数中访问局部变量?

float tot = std::accumulate(weights.begin(), weights.end(), 0.0); 
std::transform(weights.begin(), weights.end(), [](float x)->float{return(x/tot);}); 

目前,tot对于匿名函数是不可见的,所以这不会被编译。使匿名函数可见的局部变量的最佳方式是什么?

+0

对不起,0应该是0.0!编辑 – bd1

回答

39

您需要关闭。

float tot = std::accumulate(weights.begin(), weights.end(), 0); 
std::transform(weights.begin(), weights.end(), [tot](float x)->float{return(x/tot);}); 

在这种情况下,tot是通过值捕获的。 C++ 11个lambda表达式支持捕获由:

  1. [x]
  2. [&x]参考
  3. 通过参考当前在范围内的任何变量[&]
  4. 相同3,但通过值[=]

你可以在逗号分隔的列表[x, &y]中混合上述任何一个。

+0

太棒了!在STL中有关于C++ 11匿名函数用法的很好的Web /书籍参考?我在网上发现的很多内容都是匿名函数的过时替代方法,或者是随机发布的博客。 – bd1

+1

@ bd1 C++ 0x上的维基百科实际上相当不错。此外,公众可以使用的最后一个标准草案被称为n3424。不幸的是,目前还没有关于C++ 0x的书籍。 – pmr

+0

如果你用'[=]'做了一个闭包,并且它将封装范围中的_all_变量复制,那么它是否包含全局变量?它什么时候停止上升范围阶梯? –

2

您需要添加tot的“捕获列表”:

float tot = std::accumulate(weights.begin(), weights.end(), 0); 
std::transform(weights.begin(), weights.end(), [tot](float x)->float{return(x/tot);}); 

或者您可以使用捕捉默认捕捉tot含蓄:

float tot = std::accumulate(weights.begin(), weights.end(), 0); 
std::transform(weights.begin(), weights.end(), [=](float x)->float{return(x/tot);}); 
8

拉姆达可以“捕获”变量从环境范围:

[ ..., N, ... ](int a, int b) -> int { return (a + b) * N; } 
^^^^^^^^^^^^^ ^^^^^^^^^^^^  ^^^^ 
captured vars local params  ret.type 

您可以获取或者你可以使用特殊的语法[=][&]来捕获环境范围内的任何东西,即任何你实际上最终使用的东西。

+0

如果我将lambda作为函数参数解析,该怎么办?它会抛出一个错误,说lambda函数不是该参数的正确类型。 – Acidic

+0

@酸:因为你不能说lambda表达式的*类型,所以很难有*函数*其参数是闭包类型。通常,如果需要管理不同类型的可调用集合,可以使用函数*模板*来推断类型,或者使用类型擦除包装器,例如'std :: function'。 –