具有空捕获列表的lambda如何能够引用到达范围名称?

时间:2015-11-21 23:11:06

标签: c++ lambda c++14 language-lawyer

在C ++ 14标准§5.1.2/ 12中,它显示了一个lambda表达式的示例,该表达式似乎能够引用到达范围的变量x,即使:

  1. 捕获列表为空,即没有capture-default
  2. 评论说“它不会捕获x
  3. 以下是示例:

    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用法可能导致隐式捕获。 - 结束记录]

1 个答案:

答案 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参数是依赖,因此为了理智而被认为是被捕获的。