可以在 C++11 lambda 中隐式捕获参数包吗?
Posted
技术标签:
【中文标题】可以在 C++11 lambda 中隐式捕获参数包吗?【英文标题】:Can a parameter pack be captured implicitly within C++11 lambdas? 【发布时间】:2012-12-25 14:36:47 【问题描述】:有谁知道以下对“ts”的隐式捕获是否格式正确:
template<class ... Ts> void bar(Ts ... ts)
template<class ... Ts> int foo(Ts ... ts)
auto L = [=] ()
bar(ts...);
;
L();
return 0;
int g = foo(1, 2, 3);
标准是否在任何地方明确说明不应该形成良好的格式?
【问题讨论】:
我知道您可以显式捕获它们,但我还没有看到任何“无论您可以显式捕获什么,您都可以隐式捕获,反之亦然”的效果。 如果格式正确,相信会导致无限递归。 :-) 我不确定标准对此有何规定。我希望这是未定义的行为。 ;-) 如果是,这意味着解析该代码允许有任何结果,即使 lambda 中的 pack 表达式格式正确。 :-) 感谢无所不能 - 我修复了无限递归问题。 GC 4.7.3 好像不支持了。 【参考方案1】:14.5.3/6:
不是
sizeof...
表达式的包扩展的实例化产生一个列表 E1, E2, ..., EN ,其中 N 是包扩展参数中的元素数。每个 Ei 是通过实例化模式并用其第 i 个元素替换每个包扩展参数来生成的。所有的 Ei 都成为封闭列表中的元素。
无论您是否被允许显式捕获一个包(您可以,使用[ts ...]
),扩展的一般规则将导致捕获列表的每个元素。
【讨论】:
或[&ts...]
。此外,这一段讲述了包扩展规则,但没有说明任何有关捕获参数包规则的有用信息......恕我直言,它没有回答这个问题。【参考方案2】:
我猜它的格式很好,我没有找到一个直截了当的陈述(在某些情况下,措辞有时缺乏清晰/说明)但我猜它可能是推断出来的:
§5.1.2/23:
捕获后跟省略号是包扩展 (14.5.3)。 [ 例子:
template<class... Args>
void f(Args... args)
auto lm = [&, args...] return g(args...); ;
lm();
后跟省略号的捕获,在 lambda-capture 中暗示—结束示例]
args
,是捕获的示例(在本例中为显式),并且值得注意的事实是args
是一个参数包标识符。这个简短的段落的唯一作用是描述 lambda-captures 如何保持包扩展,这表明参数包可以被捕获,即使其目的不是允许它们被俘。
§5.1.2/12:
实体被捕获,如果它被显式或隐式捕获。[...]
§3/3:
实体是值、对象、引用、函数、枚举器、类型、类成员、模板、模板特化、命名空间、参数包或this。
据此,我假设 参数包是可以显式或隐式捕获的实体,因此应适用与普通变量相同的捕获规则,但参数包应相应扩展。
我猜您的问题(以及相同的论点)同样适用于参考变量,例如 (It is unspecified whether or not a reference requires storage. §8.3.2/4)。当您被允许或不允许在 lambda 中引用参数包 identifier 时,您似乎很感兴趣。
对于外部范围内的引用变量,您也可以这样想,因为您可以访问它们,但甚至不能访问原始变量的标识符。
它们就像参数包一样空灵。
【讨论】:
capture 是在子句开头定义的语法结构:capture: identifier |&
*标识符* | this
。标准中很少有这样的通用术语……并且省略号需要在语法中的某个地方出现。尽管隐式捕获变量涉及使用标识符对其进行命名,但这并不意味着这样的子表达式形成捕获。此外,capture 产生式与std::forward<T>(o)...
等更大表达式的扩展不匹配,因此,5.1.2/12 无法应用。
@Potatoswatter,我没有明白您要指出的内容,抱歉。我强调 5.1.2/12 只是为了强制执行这一点,即使标准在那里将捕获分为两种,这两种仍然可以被视为更广泛意义上的捕获,因此 5.1.2/23 是关于两者,而不是一个特别。此外,参数包只能由标识符引用,因此我认为该子句没有问题。
斜体术语仅指语法结构。 “捕获”与“捕获的实体”不同,没有裁判的余地。抱歉,我的意思是 5.1.2/23 不能申请,而不是 5.1.2/12。
@Potatoswatter,关于您的第一条评论,当我说“在 lambda 中暗示 args 是捕获的一个示例”时,我在 []
谈论 args
。当那里不存在时,lambda 体内的包扩展意味着相同的 args...
隐含在 []
中,当它被隐式捕获时。
@Potatoswatter,我可能对您所说的“5.1.2/23 不适用”的意思感到非常困惑。如果该子句不能解释如何隐式捕获参数包,我认为它也无助于显式,因此该段落没有任何意义。以上是关于可以在 C++11 lambda 中隐式捕获参数包吗?的主要内容,如果未能解决你的问题,请参考以下文章