web-dev-qa-db-ja.com

ラムダの暗黙的なキャプチャは、構造化バインディングから宣言された変数で失敗します

次のコードを使用すると、コンパイルエラーが発生しますC2065 'a': undeclared identifier(Visual Studio 2017を使用):

[] {
    auto [a, b] = [] {return std::make_Tuple(1, 2); }();
    auto r = [&] {return a; }(); //error C2065
}();

ただし、次のコードはコンパイルされます。

[] {
    int a, b;
    std::tie(a, b) = [] {return std::make_Tuple(1, 2); }();
    auto r = [&] {return a; }();
}();

2つのサンプルは同等であると思いました。コンパイラのバグですか、それとも何か不足していますか?

41

コアの問題231 構造化されたバインディングが変数の名前にならないように標準を変更し、キャプチャできないようにしました。

P0588R1 のラムダキャプチャ表現の再定式化により、この禁止事項が明確になります。

ラムダ式[...]が構造化バインディングを(明示的または暗黙的に)キャプチャする場合、プログラムの形式は正しくありません。

委員会がそのようなキャプチャがどのように機能するかを正確に把握している間、この表現はおそらくプレースホルダーであることに注意してください。

以前の答えは歴史的な理由のために保持されました:


これは技術的にはコンパイルできるはずですが、標準にはバグがあります。

規格では、ラムダは変数のみをキャプチャできるとしています。そしてそれは非タプルのような構造化バインディング宣言が変数を導入しないと言います。名前が導入されていますが、これらの名前は変数の名前ではありません。

一方、タプルのような構造化バインディング宣言では、doesによって変数が導入されます。 auto [a, b] = std::make_Tuple(1, 2);aおよびbは、実際の参照型変数です。したがって、それらはラムダによってキャプチャできます。

明らかにこれは正常な状況ではなく、委員会はこれを知っているので、修正が近づいているはずです(ただし、構造化バインディングのキャプチャがどのように機能するかについては意見の相違があるようです)。

49
T.C.

可能な回避策は、初期化子でラムダキャプチャを使用することです。次のコードは、Visual Studio 2017 15.5で正常にコンパイルされます。

[] {
    auto[a, b] = [] {return std::make_Tuple(1, 2); }();
    auto r = [a = a] {return a; }();
}();
15
akarin64