2017-10-13 78 views
44

这将编译:为什么在lambdas中隐式捕获const int(或短裤)?

int main() { 
    const int x = 123; 
    auto g = []() { std::cout << x << "\n"; }; 
    g(); 
} 

但这:

int main(){ 
    const float x = 123; 
    auto g = []() { std::cout << x << "\n"; }; 
    g(); 
} 

生产:

"error: 'x' is not captured"

为什么?

我已经在GCC(从5.0.0到8.0.0的各种版本)和Clang(从4.0.0到6.0.0的各种版本)上测试过它。它在所有情况下表现相同。

+1

http://en.cppreference.com/w/cpp/language/lambda您需要指定要捕获的变量 – StijnvanGaal

+7

@StijnvanGaal:我对OP知道的印象。 – Bathsheba

+1

这是什么编译器和版本? – deviantfan

回答

37

Lambda的作用域可以隐式捕获其到达范围内的变量。

您的变量处于到达范围之内,因为它们是定义lambda的(主)函数的本地。

但是,也有在其中变量可以通过该机制来捕获某些标准,如在[expr.prim.lambda]/12提到:

A lambda-expression with an associated capture-default that does not explicitly capture this or a variable with automatic storage duration [..], is said to implicitly capture the entity (i.e., this or a variable) if the compound-statement:

-odr-uses ([basic.def.odr]) the entity, or

-names the entity in a potentially-evaluated expression ([basic.def.odr]) where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression.

最重要的部分是在[expr.const]/2.7

A conditional-expression e is a core constant expression unless the evaluation of e , [..] would evaluate one of the following expressions:

an lvalue-to-rvalue conversion ([conv.lval]) unless it is applied to:

a non-volatile glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression.

所以const int被一个核心常量表达式const float不是。

此外[expr.const]1826提到:

A const integer initialized with a constant can be used in constant expressions, but a const floating point variable initialized with a constant cannot.

了解更多在Why is a const variable sometimes not required to be captured in a lambda?

+2

你有(2)(除了链接整个标准 - 尊重!)的ref?这似乎是在正确的路线。有一个upvote。 – Bathsheba

+1

@Bathsheba§5.1.2 - (12) – bolov

+0

@Bathsheba,但我仍然无法使段落的正面或反面... – bolov

9

C++ 14草案N4140 5.1.2.12 [expr.prim.lambda]:

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.

另外,.open-std.org

A const integer initialized with a constant can be used in constant expressions, but a const floating point variable initialized with a constant cannot. This was intentional, to be compatible with C++03 while encouraging the consistent use of constexpr. Some people have found this distinction to be surprising, however.

It was also observed that allowing const floating point variables as constant expressions would be an ABI-breaking change, since it would affect lambda capture.

相关问题