覚え書き。
C++のlambdaでは、lambda記述した位置のスコープの変数にlambdaで定義したメソッドの中からアクセスすることができる。ただし、デフォルトでは無効なので、lambdaの外の変数をキャプチャすることを明示しなければならない。以下、サンプルコード。
#include <iostream>
#include <functional>
int main(int argc, char *argv[]) {
std::string msg = "Hello";
// ERROR : not captured
// std::function<void()> f0 = []() {
// std::cout << msg << std::endl;
// };
// f0();
// refer copied msg
std::function<void()> f1 = [=]() {
std::cout << msg << std::endl;
};
f1();
msg += " World";
f1(); // copied msg is not modified
// refer original msg via reference
std::function<void()> f2 = [&]() {
msg += "!";
std::cout << msg << std::endl;
};
f2();
f2();
f2();
// msg is modified by f2()
std::cout << msg << std::endl;
return 0;
}
[=]で変数をキャプチャする場合、lambdaで関数オブジェクトを作成するときに、その変数が値渡しされる。なので、関数オブジェクト作成後に元の変数が変更されても、既にコピー済みの値を見ているlambdaの中には影響がない。
[&]で変数をキャプチャした場合、lambdaで関数オブジェクトを作成するときに、その変数が参照渡しされる。なので、関数オブジェクト作成後に元の変数が変更されれば、lambdaの中も影響を受ける。また、lambdaの中でキャプチャした変数を変更すると、lambdaの外も影響を受ける。
ちなみにlambdaを使わないで書くと、以下のような感じになる。
#include <iostream>
int main(int argc, char *argv[]) {
std::string msg = "Hello";
// refer copied msg
struct F1 {
const std::string msg;
F1(std::string& msg) : msg(msg) {}
void operator()() {
std::cout << msg << std::endl;
}
} f1(msg);
f1();
msg += "World";
f1(); // copied msg is not modified
// refer original msg via reference
struct F2 {
std::string& msg;
F2(std::string& msg) : msg(msg) {}
void operator()() {
msg += "!";
std::cout << msg << std::endl;
}
} f2(msg);
f2();
f2();
f2();
// msg is modified by f2()
std::cout << msg << std::endl;
return 0;
}
テンプレートしかり、lambdaしかり、記述が楽になるのは間違いないけど、あくまで人間の代わりにコンパイラが書いてくれるだけなので、コンパイラがどんなコードを吐くのか考えて使う必要はあるね。
0 件のコメント:
コメントを投稿