【问题标题】:Dependent Expression and ODR-use in a Generic Lambda in C++14C++14 通用 Lambda 中的依赖表达式和 ODR 使用
【发布时间】:2017-03-03 15:17:54
【问题描述】:
   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 段的示例,我通过两种方式对其进行了修改:

  • 首先,函数f() 的两个版本都有一个int 作为第一个参数,所以变量x 在任何情况下 odr-used
  • 其次,我删除(注释掉)了 lambda g2 中的 capture-default

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

  • 这不应该是编译时错误,因为存在依赖表达式并且没有 capture-default?也就是说,变量x 需要被捕获,但它不能被捕获(假设g2 调用具有两种参数,即产生sizeof(a)=1 和其他sizeof(a)>1)。

  • 或者依赖表达式隐式捕获变量的条件是否仅在存在 capture-default 时适用?这意味着,如果没有 odr-use(即,在函数 f() #2 中没有 const int&),无论 capture-default。那么,依赖表达式的第二个条件不是没用吗?

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

一个 lambda-expression 具有关联的 capture-default,它没有明确地捕获 this 或变量具有自动存储持续时间(这不包括任何已发现引用 init-capture 关联的非静态数据成员的 id-expression),据说 隐式捕获实体(即this或变量)如果复合语句

  • odr-使用 (3.2) 实体,
  • 在潜在求值表达式 (3.2) 中命名实体,其中封闭的完整表达式取决于在 lambda 表达式 的到达范围内声明的通用 lambda 参数。强>

注意:lambda g 不会捕获变量 x,因为它在 f(x) 中没有odr-used(请参阅 C++14 标准 (ISO/IEC 14882:2014),第 5.1.2 节,第 13 段)

链接:

【问题讨论】:

    标签: c++ lambda c++14 auto one-definition-rule


    【解决方案1】:

    此代码是否符合标准?

    是的。规则是:

    如果 lambda-expression 或泛型 lambda odr 的函数调用运算符模板的实例化,则使用 (3.2) this 或带有 从其到达范围的自动存储持续时间,该实体应由 lambda-expression 捕获。

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

    变量x 的名称显示为潜在评估表达式ex 是由exodr-used 除非应用左值到右值转换 (4.1) 到 @987654326 @ 产生一个不调用任何非平凡的常量表达式(5.20) 函数,如果x 是一个对象,ex 是表达式e 的潜在结果集的一个元素,其中左值到右值转换 (4.1) 应用于e,或者e 是丢弃值表达式(第 5 条)。

    x 是一个整数常量,用于应用左值到右值转换的表达式中,因此不使用 odr。由于它不是 odr-used,因此您没有捕获它并不是错误。

    如果f 的重载通过引用获取其第一个参数,则格式错误-调用运算符的实例化 odr-使用x,但事实并非如此捕获,使其格式错误。


    您引用的部分与您修改后的示例无关。它仅指“具有关联 capture-defaultlambda-expression ”。但是您的 lambda 没有 capture-defaultcapture-default=&,介绍人[] 没有默认捕获。但是,如果我们有 [=][&],则该部分将解释为什么会捕获 x

    【讨论】:

    • 换句话说,capture-default 案例捕获它是安全的,因为您无法真正判断依赖表达式是否会成为 odr-use 或直到实例化时间,如果[=][&] 给你一个“丢失捕获”错误,那就太愚蠢了。
    • @Barry 这就是我的想法,但如果这是正确的,我的示例将在有或没有捕获变量 x 的情况下编译和行为完全相同(有或没有 capture-default): 1) 没有 capture-default 变量 x 不会被捕获,因为它不是 odr-used 2) 使用 capture-default变量 x 被捕获是因为依赖表达式(即使它不是 odr-used 在函数 f() 的两个版本中的任何一个中)。因此,捕获变量x 取决于(在这种情况下)程序员是否放置 capture-default,而不是取决于 lambda 是否“需要它”(odr-uses i> 等)
    • @T.C.这是否意味着变量x 应该仅仅因为依赖表达式而被捕获,即使没有可能的odr-use?顺便说一句,我喜欢你的“先发制人”捕捉方法。我想我这样理解更好。如果存在可以使变量x 成为odr-used 的依赖表达式,则应捕获变量x 以防万一,无论是否存在capture-default 与否。它是否正确?但是,我不确定标准第 5.1.2 节第 12 段的第二个项目符号的措辞是否有助于遵守这一点(尽管措辞对我来说很难)。
    • 我用一个表格和一个试图总结所有内容的问题更新了我的帖子(也许我的误解来自于不知道编译器能够确切了解依赖表达式)
    • @JoséLuis Capture 是在您编写 lambda 时确定的,但编译器在实际实例化之前无法确定依赖表达式是否涉及 odr-use。因此,使用默认捕获(本质上说“嗨编译器,请捕获此 lambda 需要的所有内容”),lambda 将捕获可能需要的所有内容。 OTOH,程序员比编译器更了解代码,所以如果你知道不会有 odr-use,你可以省略捕获,编译器不会妨碍你,直到你真正尝试使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-04
    • 2014-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多