4

特定の関数呼び出しによって作成されたメンバー変数としてラムダがある状況があります。問題は、これを操作の一部としてキャプチャすることです。後で、オブジェクト全体をコピーできるようにしたいと思います...

ただし、コピーの時点では、ラムダがどのように作成されたかはわかりません(異なるコードパスを介していくつかの場所で定義されている可能性があります)。したがって、コピーコンストラクターに何を入れるかについては少し戸惑っています。理想的には、ラムダのキャプチャを、作成された新しい「this」に「再バインド」したいと思います。

これは可能ですか?

サンプルコードは次のとおりです。

#include <iostream>
#include <string>
#include <functional>

class Foo
{
  public:

    Foo () = default;
    ~Foo () = default;

    void set (const std::string & v)
    {
        value = v;
    }

    void set ()
    {
        lambda = [&]()
        {
            return this->value;
        };
    }

    std::string get ()
    {
        return lambda();
    }


    std::string value;
    std::function <std::string (void)> lambda;
};

int main ()
{
    Foo foo;

    foo.set ();
    foo.set ("first");

    std::cerr << foo.get () << std::endl; // prints "first"

    foo.set ("captures change");

    std::cerr << foo.get () << std::endl; // prints "captures change"

    Foo foo2 (foo);
    foo2.set ("second");

    std::cerr << foo.get () << std::endl; // prints "captures change" (as desired)
    std::cerr << foo2.get () << std::endl; // prints "captures change" (I would want "second" here)

    return 0;
}

前もって感謝します。

4

2 に答える 2

5

表示されている問題は、thisポインターがラムダにキャプチャされているが、別のオブジェクトから関数のコピーを実行していることです。両方のオブジェクトが存在するため、この例では機能していますが、発生するのを待っているダングリングポインタです。

これを行う最もクリーンな方法はstd::function、クラスへのポインターの引数を取るようにラムダとラムダを変更し、これをキャプチャする代わりに、渡されたポインターを使用することです。ラムダの内容に応じて、値をキャプチャすることを選択できます。

class Foo
{
  public:

    Foo () = default;
    ~Foo () = default;

    void set (const std::string & v)
    {
        value = v;
    }

    void set ()
    {
        lambda = [](Foo* self)
        {
            return self->value;
        };
    }

    std::string get ()
    {
        return lambda(this);
    }


    std::string value;
    std::function <std::string (Foo*)> lambda;
};

IDEOneでの例

于 2012-08-02T13:23:14.757 に答える
3

クロージャーを変更することはできないと思います。関数が別のオブジェクトを操作する必要がある場合は、関数への引数としてオブジェクトへのポインターを渡す必要があります。

class Foo
{
  public:

    Foo () = default;
    ~Foo () = default;

    void set (const std::string & v)
    {
        value = v;
    }

    void set ()
    {
        lambda = [](Foo* t)
        {
            return t->value;
        };
    }

    std::string get ()
    {
        return lambda(this);
    }

    std::string value;
    std::function <std::string (Foo*)> lambda;
};
于 2012-08-02T13:21:47.700 に答える