web-dev-qa-db-ja.com

const int(またはshorts)が暗黙的にラムダでキャプチャされるのはなぜですか?

これはコンパイルします:

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();
}

生成する:

「エラー: 'x'がキャプチャされていません」

どうして?

私はGCC(5.0.0から8.0.0までのさまざまなバージョン)とClang(4.0.0から6.0.0までのさまざまなバージョン)の両方でテストしました。すべての場合で同じように動作します。

44
rubix_addict

Lambdaのスコープは、その到達スコープ内の変数を暗黙的にキャプチャできます。

変数は、ラムダを定義する(メイン)関数に対してローカルであるため、到達範囲内にあります。

ただし、 [expr.prim.lambda]/12 で説明されているように、このメカニズムを介して変数をキャプチャできる特定の基準があります。

これまたは変数with with auto storageduration [..]を明示的にキャプチャしない、関連付けられたcapture-defaultを持つラムダ式は、次の場合、エンティティ(つまり、これまたは変数)を暗黙的にキャプチャします。

-odr-uses([basic.def.odr])エンティティ、または

-エンティティに名前を付ける評価される可能性のある式([basic.def.odr])で、完全な式を囲む式が総称 lambdaに依存するlambda-expression の到達範囲内で宣言されたパラメーター。

最も重要な部分は [expr.const] /2.7 にあります:

条件式eは、コア定数式です。ただし、e、[..]の評価で次の式のいずれかが評価される場合を除きます。

以下に適用されない限り、左辺値から右辺値への変換([conv.lval])

integral または列挙 type の不揮発性glvalueは、定数で初期化された、前の初期化を持つ不揮発性constオブジェクトを参照します式。

そう const intコア定数式であり、const float ではありません。

さらに [expr.const] 1826 言及:

定数で初期化されたconst整数は定数式で使用できますが、定数で初期化されたconst浮動小数点変数は使用できません

詳しくは ラムダでキャプチャする必要のないconst変数があるのはなぜですか?

38
gsamaras

C++ 14ドラフトN4140 5.1.2.12 [expr.prim.lambda]:

これを明示的にキャプチャしない関連するキャプチャデフォルトのラムダ式、または自動ストレージ期間を持つ変数(これにより、init-captureの参照を参照することが判明したid式は除外されます関連付けられた非静的データメンバー)は、複合ステートメントが次の場合にエンティティ(つまり、これまたは変数)を暗黙的にキャプチャすると言います。

odr-uses(3.2)エンティティ、または

評価される可能性のある式(3.2)内のエンティティーを指定します。ここで、囲んでいる完全式は、ラムダ式の到達範囲内で宣言された汎用ラムダパラメーターに依存します。

また、 。open-std.org

定数で初期化されたconst整数は定数式で使用できますが、定数で初期化されたconst浮動小数点変数は使用できません。これは、constexprの一貫した使用を奨励しながらC++ 03と互換性を持たせるための意図的なものです。しかし、この区別が驚くべきものであると考える人もいます。

また、ラムダキャプチャに影響を与えるため、定数式としてconst浮動小数点変数を許可すると、ABIを壊す変更になることも確認されました。

9
msc