在嵌套的 Lambda 中捕获 Lambda 的静态
Capturing a Lambda's static in a Nested Lambda
在this answer中我使用这个代码:
std::vector<std::vector<int>> imat(3, std::vector<int>(10));
std::for_each(imat.begin(), imat.end(), [&](auto& i) {
static auto row = 0;
auto column = 0;
std::transform(i.begin(), i.end(), i.begin(),
[&](const auto& /*j*/) {
return row * column++;
});
++row;
});
但我注意到在捕获 static auto row
时有一些不当行为,具体取决于编译器。
0 0 0 0 0 0 0 0 0 0
0 1 2 3 4 5 6 7 8 9
0 2 4 6 8 10 12 14 16 18
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
而Visual Studio 2015 给我一个编译时错误:
An internal error has occurred in the compiler.
如果我将捕获嵌套捕获更改为显式捕获 row
,我会收到编译器错误:
identifier in capture must be a variable with automatic storage duration declared in the reaching scope of the lambda
我可以在嵌套的 lambda 中捕获 static
吗?貌似还行,就是问题太多了!
编辑:
如果我更改嵌套的 lambda 的参数类型,我 可以 得到 Visual Studio 2015 进行编译并提供与 Clang 3.7.0 相同的输出从 const auto&
到 const int&
。这看起来完全无关,但它有效。
如果我尝试明确捕获 row
,这将不起作用。在那种情况下,我仍然会收到编译器错误:
identifier in capture must be a variable with automatic storage duration declared in the reaching scope of the lambda
我在这里报告了一个 Visual Studio 2015 错误:https://connect.microsoft.com/VisualStudio/feedback/details/1930409/capturing-a-lambdas-static-in-a-nested-lambda
内部编译器错误(ICE)始终是错误。
我们不需要捕获静态存储持续时间的变量,但我们确实需要捕获 odr-used 的自动变量。来自 C++ 标准草案 5.1.2
:
The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator,
but for purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming idexpressions
referring to non-static class members into class member access expressions using (*this) (9.3.1),
the compound-statement is considered in the context of the lambda-expression.
所以 row
应该在内部 lambda 中可见并且:
[...]If a lambda-expression
or an instantiation of the function call operator template of a generic lambda odr-uses (3.2) this or a
variable with automatic storage duration from its reaching scope, that entity shall be captured by the
lambda-expression.[...]
只有this
和自动存储持续时间的变量如果是odr-used才需要捕获,我们可以看到只有自动变量或this[=51才定义显式捕获=]:
The identifier in a simple-capture is looked up using the usual rules for unqualified name lookup (3.4.1);
each such lookup shall find an entity. An entity that is designated by a simple-capture is said to be explicitly
captured, and shall be this or a variable with automatic storage duration declared in the reaching scope of
the local lambda expression.
为了让 Visual Studio 和 gcc 都匹配 clang 的结果,我可以将 row
移出到全局命名空间 see it live for gcc。也正如 Fozi 指出的那样,将 const auto& /*j*/
更改为 const int& /*j*/
使其开始工作。
看起来 gcc 接受显式捕获非自动变量作为扩展,即使如此显式捕获 row
例如 [&, &row](const auto & )
仍然产生全零。
对于 gcc,如果我将 row
的定义移动到 main
,那么我会看到以下错误 (see it live):
/tmp/cchzwtQI.s: Assembler messages:
/tmp/cchzwtQI.s:1572: Error: symbol `_ZL3row' is already defined
这对我来说似乎是一个编译器错误。
我没有看到任何会使原始程序格式错误的标准部分。将 auto
更改为 int
也不应该有所不同,polymorphic lambda proposal 引入的任何更改似乎也无法解释这种差异。
在this answer中我使用这个代码:
std::vector<std::vector<int>> imat(3, std::vector<int>(10));
std::for_each(imat.begin(), imat.end(), [&](auto& i) {
static auto row = 0;
auto column = 0;
std::transform(i.begin(), i.end(), i.begin(),
[&](const auto& /*j*/) {
return row * column++;
});
++row;
});
但我注意到在捕获 static auto row
时有一些不当行为,具体取决于编译器。
0 0 0 0 0 0 0 0 0 0
0 1 2 3 4 5 6 7 8 9
0 2 4 6 8 10 12 14 16 18
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
而Visual Studio 2015 给我一个编译时错误:
An internal error has occurred in the compiler.
如果我将捕获嵌套捕获更改为显式捕获 row
,我会收到编译器错误:
identifier in capture must be a variable with automatic storage duration declared in the reaching scope of the lambda
我可以在嵌套的 lambda 中捕获 static
吗?貌似还行,就是问题太多了!
编辑:
const auto&
到 const int&
。这看起来完全无关,但它有效。
如果我尝试明确捕获 row
,这将不起作用。在那种情况下,我仍然会收到编译器错误:
identifier in capture must be a variable with automatic storage duration declared in the reaching scope of the lambda
我在这里报告了一个 Visual Studio 2015 错误:https://connect.microsoft.com/VisualStudio/feedback/details/1930409/capturing-a-lambdas-static-in-a-nested-lambda
内部编译器错误(ICE)始终是错误。
我们不需要捕获静态存储持续时间的变量,但我们确实需要捕获 odr-used 的自动变量。来自 C++ 标准草案 5.1.2
:
The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator, but for purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming idexpressions referring to non-static class members into class member access expressions using (*this) (9.3.1), the compound-statement is considered in the context of the lambda-expression.
所以 row
应该在内部 lambda 中可见并且:
[...]If a lambda-expression or an instantiation of the function call operator template of a generic lambda odr-uses (3.2) this or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression.[...]
只有this
和自动存储持续时间的变量如果是odr-used才需要捕获,我们可以看到只有自动变量或this[=51才定义显式捕获=]:
The identifier in a simple-capture is looked up using the usual rules for unqualified name lookup (3.4.1); each such lookup shall find an entity. An entity that is designated by a simple-capture is said to be explicitly captured, and shall be this or a variable with automatic storage duration declared in the reaching scope of the local lambda expression.
为了让 Visual Studio 和 gcc 都匹配 clang 的结果,我可以将 row
移出到全局命名空间 see it live for gcc。也正如 Fozi 指出的那样,将 const auto& /*j*/
更改为 const int& /*j*/
使其开始工作。
看起来 gcc 接受显式捕获非自动变量作为扩展,即使如此显式捕获 row
例如 [&, &row](const auto & )
仍然产生全零。
对于 gcc,如果我将 row
的定义移动到 main
,那么我会看到以下错误 (see it live):
/tmp/cchzwtQI.s: Assembler messages:
/tmp/cchzwtQI.s:1572: Error: symbol `_ZL3row' is already defined
这对我来说似乎是一个编译器错误。
我没有看到任何会使原始程序格式错误的标准部分。将 auto
更改为 int
也不应该有所不同,polymorphic lambda proposal 引入的任何更改似乎也无法解释这种差异。