0

この質問はおそらく、クロージャーをサポートするプログラミング言語の知識を持っている人にのみ意味があります。そうでない場合は、「なぜこれをやりたいのですか?」とコメントしないでください。そうする正当な理由はたくさんあります。

関数型言語では、既に定義されているローカル変数をキャプチャするローカル関数を定義するのが一般的です。C++ では、次のようになります (ただし、もちろん違法です)。

#include <iostream>
using namespace std;

int main()
{
    int x = 0;
    int f() { return x + 1; }

    cout << f() << endl; // would print 1

    x = 2;
    cout << f() << endl; // would print 3
}

これを可能にするために、C++11 ではラムダ関数が導入されているため、実際にはかなり適切な方法で実行できます (ただし、関数型言語で一般的に行われているほど適切ではありません ;-) ):

#include <iostream>
using namespace std;

int main()
{
    int x = 0;
    auto f = [&] () { return x + 1; };

    cout << f() << endl; // actually compiles and prints 1

    x = 2;
    cout << f() << endl; // actually compiles and prints 3
}

私の質問は次のとおりです: functionsの参照によって自由変数を自動的にキャプチャできるようになったので、ローカルで定義されたstructsに対して実行できると便利ではないでしょうか? 理想的には、次のように書けるようになりたいです。

int main()
{
    int x = 0;

    struct A 
    {
        int y;
        A(int y) : y(y) {}

        int f() { return x + y; };
    };

    A a1(1);
    A a2(2);

    cout << a1.f() << endl; // would print 1
    cout << a2.f() << endl; // would print 2

    x = 2;
    cout << a1.f() << endl; // would print 3
    cout << a2.f() << endl; // would print 4
}

私が見つけた唯一の回避策は、すべての非ローカル (フリー) 変数をコンストラクターに引数として手動で渡すことです。これは、変数がたくさんある場合は少し面倒です。

#include <iostream>
using namespace std;

int main()
{
    int x = 0;

    struct A 
    {
        // meaningful members
        int y;
        int f() { return x + y; };

        // free variables
        int & x;

        // Constructor
        A(
            // meaningful arguments
            int y,

            // capturing free variables
            int & x

        ) : y(y), x(x) {}
    };

    A a1(1, x);
    A a2(2, x);

    cout << a1.f() << endl; // prints 1
    cout << a2.f() << endl; // prints 2

    x = 2;
    cout << a1.f() << endl; // prints 3
    cout << a2.f() << endl; // prints 4
}

すべての自由変数を引数として手動で渡すことを回避する他の回避策を知っていますか、またはこれらの種類の「環境を認識する」ローカルで定義された構造体が C++ の将来の拡張で考慮されるかどうかを知っていますか? (つまり、C++1y?)

4

3 に答える 3

1

C++ のラムダ式は、一種のキャプチャ メカニズムであり、インライン オブジェクト リテラルです。正確な目的によっては、ローカルの構造体定義よりも便利な場合があります。

動機付けの例として、次のことを考えてみてください。

// environment
int offset = 42;

struct local_type {
    // capture environment 'by-hand'
    int offset;

    // purpose of the local type is to expose two overloads
    int operator()(int x) const
    { return x + offset; }

    double operator()(double x) const
    { return x + offset; }
} f { offset };

次のようにして、これを逆にすることができます。

int offset = 42;
auto f = make_overload([=](int x) { return offset + x; },
                       [=](double x) { return offset + x; });

ラムダ式はキャプチャを処理し、make_overloadコンビネータは目的のオブジェクト (ここではオーバーロードされoperator()た . (継承を利用して実装するのが最適です。)

make_overloadさまざまな場所から(再) 使用することがわかっている場合、このアプローチは理にかなっています。1 回限りの特別な用途では、ローカルであるかどうかにかかわらず、特殊な型を記述することは避けられません。

于 2013-11-10T05:21:40.620 に答える