在C ++ 14标准§5.1.2/ 12中,它显示了一个lambda表达式的示例,该表达式似乎能够引用到达范围的变量x
,即使:
x
”以下是示例:
void f(int, const int (&)[2] = {}) { } // #1
void test() {
const int x = 17;
auto g = [](auto a) {
f(x); // OK: calls #1, does not capture x
};
}
看到它does compile。它似乎取决于x
const
;如果const
被删除,它将不再编译出原因(捕获列表为空)。即使我将参数设为int
,它也不再是通用的lambda,就会发生这种情况。
即使捕获列表为空,lambda如何引用x
?这怎么可能同时显然不捕获x
(正如评论所说)?
我在这个问题上发现的最接近的事情就是其他人在评论中切向noticing。
以下是标准的完整部分5.1.2 / 12:
lambda-expression ,其关联的 capture-default 未明确捕获
this
或具有自动存储持续时间的变量(这不包括任何 id-expression 已被发现引用 init-capture 的相关非静态数据成员),据说隐式捕获实体(即,this
或变量)如果复合语句:
- odr-uses(3.2)实体,或
- 在潜在评估表达式(3.2)中命名实体,其中封闭的full-expression依赖于在 lambda-expression 的到达范围内声明的泛型lambda参数。
[示例:
void f(int, const int (&)[2] = {}) { } // #1 void f(const int&, const int (&)[1]) { } // #2 void test() { const int x = 17; auto g = [](auto a) { f(x); // OK: calls #1, does not capture x }; auto g2 = [=](auto a) { int selector[sizeof(a) == 1 ? 1 : 2]{}; f(x, selector); // OK: is a dependent expression, so captures x }; }
- 结束示例]所有这些隐式捕获的实体都应在lambda表达式的到达范围内声明。 [注意:嵌套的 lambda-expression 对实体的隐式捕获可能导致其包含 lambda-expression 的隐式捕获(见下文) )。隐含的odr用法可能导致隐式捕获。 - 结束记录]
答案 0 :(得分:10)
你有正确的引用。如果变量 odr-used ,则需要捕获变量。 ODR-use基本上意味着变量在需要定义的上下文中使用。所以要么采取它的地址,要么引用它,等等。一个关键的例外是,来自[basic.def.odr]:
变量
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] public class PublicInterfaceAnalyzer: DiagnosticAnalyzer { private static ImmutableArray<DiagnosticDescriptor> SupportedRules { get; } = new ImmutableArray<DiagnosticsDescriptor>(new DiagnosticDescriptor(id: "CheckId1", title: "Check1", messageFormat: "Placeholder text", category: "Usage", defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true)); public override void Initialize(AnalysisContext context) { context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType); } public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => SupportedRules; private void AnalyzeSymbol(SymbolAnalysisContext context) { //How to check that the functions have, say, a certain kind of //of a return value or parameters or naming? I think I know how //to do that, but I'm not sure how to get a hold of the correct //interfaces and have a collection or their (public) methods to check. //This could be one way to go, but then in Initialize //should be "SymbolKind.Method", would that be the route to take? //The following omits the code to get the interfaces and do some //of the checks as this is code in progress and the main problem //is getting hold of the function signatures of interfaces that //inherit from the marker interfaces. var symbol = (IMethodSymbol)context.Symbol; context.ReportDiagnostic(Diagnostic.Create(SupportedRules[0], symbol.Locations[0], symbol.Name)); } }
,其名称显示为可能已评估的表达式x
,除ex
外, odr-used 除非申请 左值到右值的转换(4.1)到ex
产生一个常量表达式(5.20),它不会调用任何非常重要的 函数,如果x
是一个对象,x
是表达式ex
的潜在结果集合的元素,其中应用了左值到右值的转换(4.1) e,或e是丢弃值表达式(Clause 5)。
因此,在您的示例中,在e
上应用左值到右值转换会产生一个常量表达式(因为x
是一个常量积分),因此它不会使用。由于它没有使用,因此不必捕获它。
另一方面,如果x
绑定到引用(例如x
将其参数作为f
),那么它将成为odr-使用,因此必须被捕获。在所提出的第二个示例中,const int&
的“odr-use-ness”对于通用lambda参数是依赖,因此为了理智而被认为是被捕获的。