JavaScript でこんな感じにクロージャーを使うと、
function get_func()
{
var val=0;
return function(){
return ++val;
};
}
カウンタのように動作しますが、
var a = get_func();
var b = get_func();
console.log(a()); // 1
console.log(a()); // 2
console.log(b()); // 1
console.log(b()); // 2
C++ のラムダ式で次のようにすると動作しません。
#include <iostream>
#include <functional>
std::function<int()> get_func()
{
int val = 0;
return [&]() -> int {
return ++val;
};
}
int main()
{
auto a = get_func();
auto b = get_func();
std::cout << a() << std::endl;
std::cout << a() << std::endl;
std::cout << b() << std::endl;
std::cout << b() << std::endl;
return 0;
}
クロージャーじゃないので get_func()
関数を抜けた時点で val
は無くなっており、ラムダ式が参照キャプチャしている val
は不正な位置を指しているからです。
次のようなコードがダメなのと同じです。
#include <iostream>
int* get_func()
{
int val;
return &val;
}
int main()
{
auto a = get_func();
auto b = get_func();
std::cout << ++*a << std::endl;
std::cout << ++*a << std::endl;
std::cout << ++*b << std::endl;
std::cout << ++*b << std::endl;
return 0;
}
C++ な人にはごくごく当たり前のことだし、同じに考えるほうがオカシイのだろうけど、他の言語になれた人は引っかかりそうな気がします。
最初の JavaScript のようなことを C++ でやりたければどうすべきなのでしょうかね・・・
こんな感じ?
#include <iostream>
#include <functional>
std::function<int()> get_func()
{
class func
{
public:
func() : val(0) {}
int operator()()
{
return ++val;
}
private:
int val;
};
return func();
}
int main()
{
auto a = get_func();
auto b = get_func();
std::cout << a() << std::endl;
std::cout << a() << std::endl;
std::cout << b() << std::endl;
std::cout << b() << std::endl;
return 0;
}