2011-08-27 70 views
7

例如:规则拉姆达捕获变量

class Example 
{ 
public: 
    explicit Example(int n) : num(n) {} 
    void addAndPrint(vector<int>& v) const 
    { 
     for_each(v.begin(), v.end(), [num](int n) { cout << num + n << " "; }); 
    } 
private: 
    int num; 
}; 

int main() 
{ 
    vector<int> v = { 0, 1, 2, 3, 4 }; 

    Example ex(1); 
    ex.addAndPrint(v); 
    return 0; 
} 

当你编译和运行MSVC2010这您会收到以下错误:

错误C3480: '例子:: NUM':一个lambda捕获变量必须是从一个封闭函数作用域

然而,随着克++ 4.6.2(预发布)你得到:

根据标准草案哪个编译器是正确的?

+3

请注意,您必须在这里按值来捕获'this',而不是'num'。当你使用'num'时,你真的使用'this-> num'。另请注意,MSVC没有实现lambda表达式的C++ 11措辞,因为它在2008年后实现了这一切。 –

+0

@Alexandre:捕获'this'与通过引用捕获'num'实际上是一样的。这似乎不是这里所期望的。 –

+0

// @本:很好。然而结果在这里是一样的,因为闭包不会转义addAndPrint的作用域(而且整个事情很可能在这里被内联)。 5.1.2由@dimitri引用似乎表明MSVC是正确的,因为'num'不是具有自动存储持续时间的变量。然而,这种行为很奇怪。 –

回答

7

5.1.2/9:

The reaching scope of a local lambda expression is the set of enclosing scopes up to and including the innermost enclosing function and its parameters.

和5.1.2/10:

The identifiers in a capture-list are looked up using the usual rules for unqualified name lookup (3.4.1); each such lookup shall find a variable with automatic storage duration declared in the reaching scope of the local lambda expression.

作为num既不以任何功能范围中声明也不具有自动存储的持续时间,它不能被捕获。因此VS是正确的,而g ++是错误的。

+0

感谢您的澄清。我发现g ++ 4.6.2有一些关于捕获的bug,例如'[=,this]'也在编译,他们打算修复它们为4.7.0。 –

0

标准说以下(5.1.2):

在捕获列表的标识符抬起头来使用不合格的名称查找(3.4.1)的一般规则;每个 这样的查找应该找到一个在本地 lambda表达式的范围内声明的具有自动存储持续时间的变量。

根据我的理解,GCC编译器是正确的,因为'num'处于lambda声明点的范围内。

+2

仅在范围内是不够的,它必须是具有自动存储时间的变量**。 –