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 段的示例,我以两种方式对其进行了修改:
- 首先,函数
f()
的两个版本都有一个 int
作为第一个参数,所以变量 x
是 而不是 在任何情况下都使用了 odr。
- 其次,我删除(注释掉)lambda
g2
. 中的 capture-default
此代码符合标准吗? clang 和 gcc 都编译成功。但是,在原始示例中,lambda g2
有一个 capture-default ([=]
),因此变量 x
被隐式捕获,因为有一个从属表达式(也因为它可能在函数 f() #2_original
中 odr-used)。请注意,在标准的上述段落中,有 2 个条件可以隐式捕获变量 x
(odr-use 或依赖表达式)。现在,没有 capture-default 也没有 odr-use:
这不应该是一个编译时错误吗,因为有一个依赖表达式并且没有 capture-default?也就是说,变量 x
需要被捕获,但它不能被捕获(假设 g2
使用两种参数调用,即产生 sizeof(a)=1
和其他 sizeof(a)>1
)。
或者依赖表达式隐式捕获变量的条件是否仅在存在捕获默认值时适用?这意味着,如果没有 odr-use(即,函数 f() #2
中没有 const int&
),程序将以相同的方式工作,而不管 捕获默认值。那么,第二个依赖表达式的条件岂不是没用了?
这是 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-used 在 f(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-default。 capture-default 是 =
或 &
,介绍人 []
没有 capture-default。但是,如果我们有 [=]
或 [&]
,该部分将解释为什么 x
会被捕获。
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。 - 其次,我删除(注释掉)lambda
g2
. 中的 capture-default
此代码符合标准吗? clang 和 gcc 都编译成功。但是,在原始示例中,lambda g2
有一个 capture-default ([=]
),因此变量 x
被隐式捕获,因为有一个从属表达式(也因为它可能在函数 f() #2_original
中 odr-used)。请注意,在标准的上述段落中,有 2 个条件可以隐式捕获变量 x
(odr-use 或依赖表达式)。现在,没有 capture-default 也没有 odr-use:
这不应该是一个编译时错误吗,因为有一个依赖表达式并且没有 capture-default?也就是说,变量
x
需要被捕获,但它不能被捕获(假设g2
使用两种参数调用,即产生sizeof(a)=1
和其他sizeof(a)>1
)。或者依赖表达式隐式捕获变量的条件是否仅在存在捕获默认值时适用?这意味着,如果没有 odr-use(即,函数
f() #2
中没有const int&
),程序将以相同的方式工作,而不管 捕获默认值。那么,第二个依赖表达式的条件岂不是没用了?
这是 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-used 在 f(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 expressionex
is odr-used byex
unless applying the lvalue-to-rvalue conversion (4.1) tox
yields a constant expression (5.20) that does not invoke any non-trivial functions and, ifx
is an object,ex
is an element of the set of potential results of an expressione
, where either the lvalue-to-rvalue conversion (4.1) is applied toe
, ore
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-default。 capture-default 是 =
或 &
,介绍人 []
没有 capture-default。但是,如果我们有 [=]
或 [&]
,该部分将解释为什么 x
会被捕获。