1. ホーム
  2. c++

[解決済み] ラムダキャプチャと同名のパラメータ - どちらがシャドウになるのか?(clang vs gcc)

2022-07-29 20:28:43

質問

auto foo = "You're using g++!";
auto compiler_detector = [foo](auto foo) { std::puts(foo); };
compiler_detector("You're using clang++!");

  • clang++ 3.6.0 で、それ以降の出力は "あなたはclang++を使用しています!" という警告が表示され キャプチャ foo は未使用です。

  • g++ 4.9.0 で、より新しいプリントアウト "あなたはg++を使用しています!" と警告し パラメータ foo は未使用です。

ここで、どのコンパイラがより正確にC++標準に準拠しているのでしょうか?

wandboxの例

どのように解決するのですか?

更新:一番下の引用文にあるCore chairの約束通り、そのコードは が不正な形式になっています。 :

もし 識別子 の中に シンプルキャプチャー のように表示されます。 宣言者ID のパラメータとして表示されます。 ラムダ宣言子 's パラメータ宣言節 であるため、プログラムは不正確な形式です。


しばらく前に、ラムダでの名前検索に関するいくつかの問題がありました。それらは N2927 :

新しい文言では、捕捉された実体の用途を再マップするためにルックアップに依存しなくなりました。 より明確に という解釈を否定しています。 複合ステートメント が2回で処理される、あるいはその 複合ステートメント の名前がクロージャ型のメンバに解決されるかもしれません。

ルックアップは常に ラムダ式 のコンテキストで行われ、決してクロージャ型のメンバ関数本体への変換の後では行われません。参照 [expr.prim.lambda]/8を参照してください。 :

ラムダ式 's 複合ステートメント 関数本体 ([dcl.fct.def])の関数呼び出し演算子ですが、名前検索のために、[...]のように 複合ステートメント のコンテキストで考慮されます。 ラムダ式 . [ :

struct S1 {
  int x, y;
  int operator()(int);
  void f() {
    [=]()->int {
      return operator()(this->x+y);  // equivalent to: S1::operator()(this->x+(*this).y)
                                     // and this has type S1*
    }; 
  }
};

- 終了例 ]

(この例では、lookupがクロージャ型の生成されたキャプチャメンバを何らかの形で考慮しないことも明確にしています)。

名前 foo はキャプチャーの中で(再)宣言されるのではなく、ラムダ式を囲むブロックの中で宣言されます。パラメータ foo はその外側のブロックにネストされたブロックの中で宣言されます ( [基本.スコープ.ブロック]/2 も明示的にラムダパラメータについて言及しています)。ルックアップの順序は明らかに 内側から外側のブロックへ . したがって、パラメータは選択されるべきであり、つまり、Clangは正しいのです。

もし、キャプチャをinit-captureにするとしたら、つまり foo = "" の代わりに foo の代わりにを使用した場合、答えは明確ではありません。これは、キャプチャが現在実際に の宣言を誘導しているからです。 その "block" は与えられないからです。私はこれに関してコアチェアにメッセージを送りましたが、彼は次のように答えました。

これは課題 2211 です (新しい課題リストがまもなく open-std.org サイトに表示されますが、残念ながら多くの課題に対するプレースホルダーがあるだけで、これはそのうちのひとつです; 私は月末のコナ会議までにこれらのギャップを埋めるために懸命に働いています)。CWGは、1月の電話会議でこれについて議論しました。 は、キャプチャ名がパラメータ名でもある場合、プログラムを不正な形式にするよう指示しています。