2

ラムダ式について (できれば) 簡単な質問があります。

#include <vector>
#include <algorithm>
//----------------------------------------------------------------
void DoSomething()
//----------------------------------------------------------------
{
  std::vector<int> elements;
  elements.push_back(1);
  elements.push_back(2);

  int ref = 1;
  auto printhit = [=](int iSomeNumber)
  {
    if (ref == iSomeNumber)
    {
      printf("Hit: %d\n", iSomeNumber);
    }
    else
    {
      printf("No Hit: %d\n", iSomeNumber);
    }
  };

  ref = 2;
  std::for_each(elements.begin(), elements.end(), printhit);   
}

さて、私の質問は次のとおりです。キャプチャ[=]でprinthitを定義すると、「ヒット:1」が出力されます。参照 [&] で渡すと、"Hit: 2" と出力されます。「ref」へのアクセスをどのように許可しても、「Hit: 2」が出力されるように、for_each 内で置換が行われることをどういうわけか期待していました。

誰かが私にこれを説明できますか?

ありがとう、マーカス

4

3 に答える 3

5

キャプチャは、ラムダを宣言した場所で行われます。refその時点でクラス オブジェクトを作成し、そのコンストラクターに渡す場合と同様です。

あなたの例はこれと同等です:

class Functor
{
public:
    Functor(int r) :ref(r) {}

    void operator()(int iSomeNumber) const
    {
        if (ref == iSomeNumber)
        {
            printf("Hit: %d\n", iSomeNumber);
        }
        else
        {
            printf("No Hit: %d\n", iSomeNumber);
        }    
    }
private:
    int ref;
};

void DoSomething()
//----------------------------------------------------------------
{
  std::vector<int> elements;
  elements.push_back(1);
  elements.push_back(2);

  int ref = 1;
  Functor printhit(ref);

  ref = 2;
  std::for_each(elements.begin(), elements.end(), printhit);   
}
于 2013-11-15T07:59:06.267 に答える
1

C++ 標準の次の部分が適用されると思います。

5.1.2.14:
エンティティが暗黙的にキャプチャされ、capture-default が = である場合、または & を含まないキャプチャで明示的にキャプチャされた場合、エンティティはコピーによってキャプチャされます。コピーによってキャプチャされたエンティティごとに、名前のない非静的データ メンバーがクロージャー型で宣言されます。これらのメンバーの宣言順序は規定されていません。このようなデータ メンバーの型は、エンティティがオブジェクトへの参照でない場合は対応するキャプチャされたエンティティの型であり、そうでない場合は参照される型です。[ 注: キャプチャされたエンティティが関数への参照である場合、対応するデータ メンバーも関数への参照です。—終わりのメモ]
5.1.2.21:
ラムダ式が評価されると、コピーによってキャプチャされたエンティティを使用して、結果のクロージャ オブジェクトの対応する各非静的データ メンバが直接初期化されます。(配列メンバーの場合、配列要素は添え字の昇順で直接初期化されます。) これらの初期化は、非静的データ メンバーが宣言された (指定されていない) 順序で実行されます。[ 注: これにより、破壊が構築の逆の順序で発生することが保証されます。—終わりのメモ]
于 2013-11-15T08:09:00.713 に答える
1

両方が同じように動作することのポイントは何ですか? ポイントは、参照ではなく[=]コピーによるキャプチャをサポートすることです。

利用できない場合を想像してみてください[=]: ラムダが定義されているコード内のポイントでランタイム値を知っていて、ラムダでそれを使用したい場合、その値をラムダ コードで利用できるようにするにはどうすればよいでしょうか? ローカル変数への参照によるアクセスをDoSomething()実行している間は役立つかもしれませんが、ラムダの有効期間をそれを含むローカルスコープよりも長くしたい場合、またはラムダへの将来の呼び出しに影響を与えずにの値を変更したい場合はどうすればよいでしょうか? 概念的には、言語でこれらすべてのことを禁止することもできます (変更後の使用、変更後のラムダの呼び出し、または変更後のラムダの呼び出し)。[&]refDoSomething()refrefrefrefrefラムダが使用する場所 (たとえば、割り当て解除を管理する必要のあるヒープ上、または再入可能性とスレッドセーフの問題を伴う静的バッファー内) ですが、便利にするために言語が提供する[=]. コンパイラによって生成されたラムダは、ref.

于 2013-11-15T08:29:17.917 に答える