const ReferenceとしてのLambda Capture?
質問
ラムダの表現でconst参照によってキャプチャすることは可能ですか?
たとえば、以下にマークされた課題を失敗させたいと思います。
#include <cstdlib>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string strings[] =
{
"hello",
"world"
};
static const size_t num_strings = sizeof(strings)/sizeof(strings[0]);
string best_string = "foo";
for_each( &strings[0], &strings[num_strings], [&best_string](const string& s)
{
best_string = s; // this should fail
}
);
return 0;
}
アップデート: これは古い質問であるため、これを支援するためにC ++ 14に施設がある場合は、更新するのが良いかもしれません。 C ++ 14の拡張機能により、Const Referenceによって非コンストオブジェクトをキャプチャできますか? (2015年8月)
解決
const
N3092の時点でキャプチャの文法にはありません:
capture:
identifier
& identifier
this
テキストには、Capture-by-CopyとCapture-by-Referenceのみに言及しているだけであり、いかなる種類の憲法も言及していません。
私には監視のように感じますが、私は標準化プロセスに非常に密接に従っていません。
他のヒント
キャプチャ部分は指定すべきではないと思います const
, 、キャプチャが意味するように、外側のスコープ変数にアクセスする方法のみが必要です。
指定子は、外側の範囲でより適切に指定されています。
const string better_string = "XXX";
[&better_string](string s) {
better_string = s; // error: read-only area.
}
ラムダ関数 const(その範囲で値を変更できません)したがって、変数を値でキャプチャする場合、変数を変更することはできませんが、参照はLambdaスコープにありません。
変数をファンチャーのパラメーターとして使用していない場合は、現在の関数のアクセスレベルを使用する必要があると思います。そうすべきではないと思うなら、この機能からラムダを分離してください。それはその一部ではありません。
とにかく、代わりに別のconstリファレンスを使用して、必要なものを簡単に実現できます。
#include <cstdlib>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string strings[] =
{
"hello",
"world"
};
static const size_t num_strings = sizeof(strings)/sizeof(strings[0]);
string best_string = "foo";
const string& string_processed = best_string;
for_each( &strings[0], &strings[num_strings], [&string_processed] (const string& s) -> void
{
string_processed = s; // this should fail
}
);
return 0;
}
しかし、それはあなたのラムダを現在の関数から隔離する必要があると仮定して、それを非lambdaにするのと同じです。
3つの異なるオプションがあると思います。
- const Referenceを使用しないでくださいが、コピーキャプチャを使用します
- 変更可能であるという事実を無視してください
- std :: bindを使用して、const参照を持つバイナリ関数の1つの引数をバインドします。
コピーの使用
コピーキャプチャを備えたラムダスについての興味深い部分は、それらが実際に読み取られているため、あなたが望むことを正確に行うことです。
int main() {
int a = 5;
[a](){ a = 7; }(); // Compiler error!
}
std :: bindを使用します
std::bind
関数の不安を減らします。ただし、これにより、関数ポインターを介して間接関数呼び出しにつながる可能性があることに注意してください。
int main() {
int a = 5;
std::function<int ()> f2 = std::bind( [](const int &a){return a;}, a);
}
短い方法があります。
「best_string」の前にアンパサンドはないことに注意してください。
「const std :: reference_wrapper << t >>」タイプになります。
[best_string = cref(best_string)](const string& s)
{
best_string = s; // fails
};
Clangを使用するか、このGCCバグが修正されるまで待ちます:バグ70385:const参照の参照によるラムダキャプチャは失敗します[https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385]
constを使用するには、アルゴリズムAmpersandを使用するだけで、文字列を元の値に設定します。つまり、ラムダは関数のパラメーターとして実際に定義することはありませんが、周囲のスコープには追加の変数があります...ただし、文字列を典型的なものとして定義することはありません &、&best_string](string const s) したがって, 、参照をキャプチャしようとしているだけで、そのままにしておくと最も良いでしょう。