ラムダ式の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参照により非constオブジェクトをキャプチャできますか? (2015年8月)
const
は、n3092の時点ではキャプチャの文法に含まれていません。
capture:
identifier
& identifier
this
テキストには、コピーによるキャプチャと参照によるキャプチャのみが記載されており、const-nessは一切記載されていません。
私には見落としがあるように感じますが、私は標準化プロセスにあまり厳密には従っていません。
C++ 14:
[&best_string = static_cast<const std::string&>(best_string)](const string& s)
{
best_string = s; // fails
};
C++ 17:
[&best_string = std::as_const(best_string)](const string& s)
{
best_string = s; // fails
};
キャプチャ手段はキャプチャ手段としてconst
を指定すべきではなく、外部スコープ変数にアクセスする方法のみが必要だと思います。
指定子は、外側のスコープでより適切に指定されます。
const string better_string = "XXX";
[&better_string](string s) {
better_string = s; // error: read-only area.
}
ラムダ関数はconst(スコープ内の値を変更できない)であるため、値ごとに変数をキャプチャすると、変数変更することはできませんが、参照はラムダスコープにありません。
ファンクタのパラメータとして変数を使用していない場合は、現在の関数のアクセスレベルを使用する必要があります。すべきでないと思われる場合は、ラムダをこの関数から分離してください。それはその一部ではありません。
とにかく、代わりに別の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;
}
しかし、これは、ラムダを現在の関数から分離して、非ラムダにする必要があると仮定するのと同じです。
次の3つのオプションがあると思います。
コピーキャプチャを使用したラムダの興味深い点は、それらが実際に読み取り専用であるため、希望どおりに動作することです。
int main() {
int a = 5;
[a](){ a = 7; }(); // Compiler error!
}
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
};
Constを使用すると、アルゴリズムにアンパサンドが設定され、文字列が元の値に設定されます。言い換えると、ラムダは関数のパラメーターとして自身を定義しませんが、周囲のスコープには追加の変数があります...ただし、通常の[&、&best_string](string const s)Thereforeとして文字列を定義しません。おそらくそれをそのままにして、参照をキャプチャしようとする方が良いでしょう。
Clangを使用するか、このgccのバグが修正されるまで待ちます:バグ70385:const参照の参照によるLambdaキャプチャが失敗します[ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385 ]