ラムダをよく知るために
C++0xのラムダも最終的にはstd::functionと等価なファンクタになるらしい。つまりあくまでファンクタを作る構文糖だと。
キャプチャとかあるけど結局はそれほど知らない。まぁ仕様書読んで来いって話なんだけど、やっぱり書かないと覚えないから先に書いてから確認。
ってことでいろいろ試してみた。環境はg++4.6 20100722
- 最小のラムダの構築と実行 []{}(); -> OK -> 7文字! - ラムダの比較 std::cout<<std::boolalpha<<([]{}==[]{})<<std::endl; -> OK -> false 中身が同じでもやはり等価ではないらしい - constant-expression constexpr []{}(); -> ill-formed -> constant expressionにはならない? 場所変えてもだめ constexpr auto _=[]{return 1;}; -> ill-formed -> constantなファンクタ? std::array<int,_()> arr; -> ill-formed -> <lambda()>::operator()がconstant expressionではないんだろう - constメンバとしての・・・ []()const->void{}; -> ill-formed -> operator() constはつくれなさそう? int i; const auto _=[&]{i=0;}; _(); -> OK -> 常にoperator() constらしい int i; auto _=[=]{i=0;}; -> ill-formed -> コピーで取ってきたものはすべてread-onlyらしい
とまぁいろいろやってみた。これだけだとあんまり変なことはできなさそう?
constant expressionはgccでの実装がまだ完全でないからまた変わったりするのかな?template引数をラムダで書く日は遠くない(ぇ
次は例外関係。「例外なんて...」って前までは思ってたけどいろいろ勉強していくと楽しくて最近はよく投げる。下手なエラーコードよりわかり易いし。
[]noexcept{}; -> ill-formed -> 怒られた。いい線いってると思ったが 意味としては[]throw(){};に同じ []()noexcept{}; -> OK -> 仮引数が空でも必要らしい 同様に[]()throw(){};も通る noexcept( []{} ); -> ill-formed -> ラムダは評価不可能な式らしい noexcept([]()noexcept{});も同じ auto _=[]()noexcept{}; std::cout<<std::boolalpha<<noexcept(_)<<std::endl; -> OK -> 評価したい場合はインスタンスを持たせる必要があると。 []()->void try{}catch(...){}; -> ill-formed -> 関数本体をtry-catch化するあれ どうやってもだめだった
そして驚愕だったのが次のコード
std::set_unexpected( []{std::cout<<"unexpect"<<std::endl;} ); std::set_terminate( [](std::cout<<"term"<<std::endl;} ); try { []()throw(int){throw std::exception();}(); } catch(int) {}
これ、どうなると思いますか?普通はunexpectが表示されてからtermが出てきますよね。
実行結果は直接termでした。例外仕様ガン無視です。これにはおどろいた。
もしかしたらgccの実装が不完全で、仕様だとちゃんとunexpectを呼ぶことになってるかもしれないけど・・・あとで読もう。
いろいろたのしいラムダですが、若干怪しい挙動がありました。仕様を読まないやつが悪いんですが、gccのバグだったら4.5.1とかで修正されるのでしょう。
~~~~
どーでもいいけど、関数の定義から呼出までC++0xなら7文字ですよ。これより短い言語ってなにがあるよ?