在嵌套Lambda中捕获Lambda的静态对象 [英] Capturing a Lambda's static in a Nested Lambda

查看:111
本文介绍了在嵌套Lambda中捕获Lambda的静态对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此答案中,我使用以下代码:

In this answer I use this code:

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的某些行为取决于编译器.

But I notice some misbehavior in capturing static auto row depending upon the compiler.

C 3.7.0收益率:

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 1 2 3 4 5 6 7 8 9
0 2 4 6 8 10 12 14 16 18

gcc 5.1.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 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 0

Visual Studio 2015给我一个编译时错误:

And Visual Studio 2015 gives me a compile time error:

编译器发生内部错误.

An internal error has occurred in the compiler.

如果将捕获嵌套捕获更改为显式捕获row,则会出现编译器错误:

If I change the capture nested capture to capture row explicitly I get the compiler error:

捕获中的标识符必须是在lambda的作用域内声明的具有自动存储期限的变量

identifier in capture must be a variable with automatic storage duration declared in the reaching scope of the lambda

我可以在嵌套lambda中捕获static吗?似乎合法,但是有很多问题!

Am I allowed to capture a static in a nested lambda? It seems legit, but there are so many problems!

Fozi指出了如果将嵌套的lambda的参数类型从const auto&更改为const int&,则我可以使Visual Studio 2015进行编译并提供与Clang 3.7.0相同的输出.似乎完全没有关系,但是可以.

Fozi pointed out that I can get Visual Studio 2015 to compile and give the same output as Clang 3.7.0 if I change the nested lambda's parameter type from const auto& to const int&. Which seems completely unrelated, but it works.

如果我尝试显式捕获row,则此方法无效.在那种情况下,我仍然会收到编译器错误:

This doesn't work if I try to capture row explicitly. In that case I still get the compiler error:

捕获中的标识符必须是在lambda的作用域内声明的具有自动存储期限的变量

identifier in capture must be a variable with automatic storage duration declared in the reaching scope of the lambda

我在这里报告了Visual Studio 2015错误:

I've reported a Visual Studio 2015 bug here: https://connect.microsoft.com/VisualStudio/feedback/details/1930409/capturing-a-lambdas-static-in-a-nested-lambda

推荐答案

内部编译器错误( ICE )始终是一个错误.

An Internal Compiler Error(ICE) is always a bug.

我们不需要捕获静态存储持续时间的变量,但是需要捕获

We don't need to capture variables of static storage duration but we do need to capture automatic variables that are odr-used. From the draft C++ standard section 5.1.2:

lambda表达式的复合语句产生函数调用运算符的函数体(8.4), 但出于名称查找(3.4)的目的,确定其类型和值(9.3.2)并转换idexpressions 使用(* this)(9.3.1)将非静态类成员引用到类成员访问表达式中, 在lambda表达式的上下文中考虑复合语句.

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中可见,并且:

so row should be visible within the inner lambda and:

[...]如果是lambda表达式 或通用lambda odr的函数调用运算符模板的实例化-使用(3.2)this或a 变量具有自达到范围以来的自动存储期限,则该实体应由 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和自动存储持续时间变量的捕获(如果使用了它们),并且我们可以看到显式捕获仅针对自动变量或 this 定义:

Capture is only required for this and variables of automatic storage duration if they are odr-used and we can see that explicit capture is only defined for automatic variables or this:

使用用于不合格名称查找的常规规则来查找简单捕获中的标识符(3.4.1); 每个这样的查找都将找到一个实体.由简单捕获指定的实体被称为是显式的 捕获的,并且应是此变量或具有自动存储持续时间的变量,且在 本地lambda表达式.

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移到全局名称空间,

For both Visual Studio and gcc to match the results of clang I can move row out to the global namespace, see it live for gcc. Also as Fozi points out changing const auto& /*j*/ to const int& /*j*/ makes it start working.

看起来gcc接受显式捕获非自动变量作为扩展,并且即使然后显式捕获row,例如[&, &row](const auto & )仍会产生全零.

It looks like gcc accepts explicit capture of non-automatic variables as an extension and even then explicitly capturing row for example [&, &row](const auto & ) still produces all zeros.

对于gcc,如果我将row的定义移到main,那么我会看到以下错误( 实时观看 ):

Further for gcc if I move the definition for row to main then I see the following error (see it live):

/tmp/cchzwtQI.s: Assembler messages:
/tmp/cchzwtQI.s:1572: Error: symbol `_ZL3row' is already defined

在我看来这是编译器错误.

Which seems like a compiler error to me.

我看不到该标准的任何部分会使原始程序格式错误.将auto更改为int也不会有所不同,并且与

I don't see any portion of the standard that would make the original program ill-formed. Nor should changing the auto to int make a difference and non of the changes introduced by polymorphic lambda proposal would seem to explain this difference either.

这篇关于在嵌套Lambda中捕获Lambda的静态对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆