C++14 中泛型 Lambda 中的依赖表达式和 ODR 使用

Dependent Expression and ODR-use in a Generic Lambda in C++14

   void f(      int , const int (&)[2] = {}) { } // #1 
   void f(      int , const int (&)[1]     ) { } // #2 
// void f(const int&, const int (&)[1]     ) { } // #2_original 

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 ??? 
    }; 
} 

这是 C++14 标准 (ISO/IEC 14882:2014) 第 5.1.2 节第 12 段的示例,我以两种方式对其进行了修改:

此代码符合标准吗? clang 和 gcc 都编译成功。但是,在原始示例中,lambda g2 有一个 capture-default ([=]),因此变量 x 被隐式捕获,因为有一个从属表达式(也因为它可能在函数 f() #2_originalodr-used)。请注意,在标准的上述段落中,有 2 个条件可以隐式捕获变量 xodr-use 或依赖表达式)。现在,没有 capture-default 也没有 odr-use:

这是 C++14 标准 (ISO/IEC 14882:2014),第 5.1.2 节,第 12 段(强调我的):

A lambda-expression with an associated capture-default that does not explicitly capture this or a variable with automatic storage duration (this excludes any id-expression that has been found to refer to an init-capture’s associated non-static data member), is said to implicitly capture the entity (i.e., this or a variable) if the compound-statement:

  • odr-uses (3.2) the entity, or
  • names the entity in a potentially-evaluated expression (3.2) where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression.

注意:lambda g 不捕获变量 x 因为它不是 odr-usedf(x) 中(参见 C++ 14 标准(ISO/IEC 14882:2014),第 5.1.2 节,第 13 段)

链接:

Is this code Standard-compliant?

是的。规则是:

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.

lambda odr 是否使用 x?不,因为 [basic.def.odr]:

A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.20) that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression (Clause 5).

x 是一个整型常量,用在应用了左值到右值转换的表达式中,因此不使用 odr。因为它不是 odr-used,所以你没有捕获它不是错误。

如果 f 的重载通过引用获取其第一个参数,则它的格式不正确 - 调用运算符 的实例化将 odr-use x,但未捕获,使其格式错误。


您引用的部分与您修改后的示例无关。它仅指"A lambda-expression with an associated capture-default"。但是你的 lambda 没有 capture-defaultcapture-default=&,介绍人 [] 没有 capture-default。但是,如果我们有 [=][&],该部分将解释为什么 x 会被捕获。