2016-08-29 6 views
15

ラムダによってキャプチャされた変数にアクセス(読み取り専用)することはできますか?ラムダによって取り込まれた変数にアクセス(読み込み専用)できますか?

これは動作しません:

std::function<double (const double)> plus (const double a) { 
    return [a] (const double b) -> double { 
     return a+b; 
    }; 
} 

auto plus5 = plus(5); 
cout << plus5.a << endl; 
+4

ラムダと 'std :: function'のどちらも... – Jarod42

+7

これはstd関数に格納した後ではありません。それがなければ、私はC++で恐ろしい(しかし合法的な)ハックでそれを行うことができます。しかし、私はあなたがそれを使用するかもしれないので、どのようにあなたに伝えるのは恐ろしい人でしょう。 – Yakk

+0

あなたはファンクタを探しているかもしれません –

答えて

16
auto plus(double a) { 
    using R = struct { 
    double a; 
    double operator()(double b)const{return b+a;} 
    }; 
    return R{std::move(a)}; 
} 

live example

std::functionはラムダではなく、ラムダはstd::functionではありません。彼らはお互いに働いていますが、一方の言葉を使ってもう一方の言葉を参照するのは助けになることの反対です。

+0

単純に構造体に名前を付ける代わりに '使用する 'のはなぜですか? – StoryTeller

+1

@StoryTeller私はラムダをできるだけ近く模倣しようとしています。私の元の試みは、匿名の構造体を直接返すことでしたが、return文で構造体を宣言することはできません。 ;) – Yakk

+0

ありがとうYakk、これは素晴らしいです!構造体をいくつかのC++関数インタフェースから継承させることが可能なのですか? 'a'へのアクセスがもう必要ないときに' std :: function'を特殊化/変換することができますか? – user357269

13

これは、ラムダが使用されるべきかではありません。

ラムダのインターフェイスは、その機能シグネチャです。キャプチャは実装の詳細とみなされ、ユーザーには表示されません。

あなたがキャプチャへの明示的なアクセスをしたい場合は、独自の関数オブジェクトを作成し、それに応じてそれぞれのデータメンバを公開:

struct MyPlus { 
    double a; 
    MyPlus(double x) : a(x) {} 
    double operator()(const double b) 
    { 
     return a+b; 
    } 
}; 

auto plus5 = MyPlus(5); 
std::cout << plus5.a; 
+1

これはちょうど私がラムダに避けるために使用する定型文の一種です – user357269

+5

@ user357269はい。しかし、これは非常に特殊な状況で、ラムダは単に扱うことができません。だから私は、より冗長で強力な汎用的なアプローチに落ちることが最善の選択肢であると思います。 – ComicSansMS

9

"確かにstd関数に格納した後ではありませんが、C++で恐ろしい(しかし法的な)ハックをすることができました17しかし、あなたがそれを使うかもしれないからです。 - Yakk

ヤックのカルマを和らげましょう。ここであなたは間違いなく野生に放たしたくないC++ 14ソリューションのコンセプトの証明です:

auto magic = [a, b](auto &&... args) mutable -> decltype(auto) { 
    return makeOverload(

     // Capture access boilerplate 
     [&](cap_<0>) -> auto& { return a; }, 
     [&](cap_<1>) -> auto& { return b; }, 

     // Actual function 
     [&](int p) { 
      return "[" + std::to_string(a) + ", " + b + "](" + std::to_string(p) + ")"; 
     } 

    )(std::forward<decltype(args)>(args)...); 
}; 

makeOverloadはファンクタの任意の数をとり、単一のものにそれらをブレンド。私はthis blog postからそのアイデアを借用し、実際に動作させるためにコメントセクションの助けを借りて助けてくれました。

結果ファンクタは、cap<N>タグと実際の関数のパラメータの間のタグディスパッチに使用されます。したがって、magic(cap<0>)を呼び出すと、対応するキャプチャされた変数、つまりaが吐き出されます。機能の実際の動作は、もちろん、magic(123)への通常の呼び出しでアクセス可能です。

ボーナスとして、外側のラムダはmutableであり、キャプチャアクセサは参照によって戻されます。キャプチャされた変数には実際に読み書き可能なアクセス権があります。

あなたはこの生き物をColiru right hereの自然生息地で観察することができます。

関連する問題