Boost.Fusion, Boost.Phoenixのメンテナになりました
今朝見慣れないメールがいくつか飛んできていて、その中でJoel de Guzman(FusionとかPhoenixとかSpiritとかのAuthor)が、「君をメインメンテナとしてコミット権追加しといたから、ヨロシク」ってなてました。
Boostの開発はgithubに移行してからpull-requestすれば誰でも参加できるものだったので、特にコミット権は不要で(ただしコミット権持った人が反応しないとめっちゃ滞る)、まぁいいかなってFusionとか100個ぐらいpull-requestガシガシ投げてたんですが、最近Phoenixもいじるようになって流石に面倒になってきたんでしょうか... 当のJoelはSpirit.X3の開発に専念したいみたいですし。
コミット権あっても何でもやっていいわけではないので、明らかなtypoとかテスト追加とかは直接やるとして、結局はpull-request出してセルフマージしていく感じになると思います。明らかな破壊的変更は他の人のレビューも待って誰かにマージしてもらう感じで。
おわかりいただけただろうかhttps://t.co/Xgqj5Og9GE
— にゃははー (@Flast_RO) 2016年5月3日
インクルードガードとpragma once
C++ Advent Calendar 2015の5日目です。
前C++時代から近代C++に至るまで、ヘッダファイルの重複インクルード排除のために通称インクルードガードというものが使われてきました。
#ifndef YOUR_VERY_VERY_AWESOME_LIBRARY_HEADER_H #define YOUR_VERY_VERY_AWESOME_LlBRARY_HEADER_H #endif // YOUR_VERY_VERY_AWESOME_LIBRARY_HEADER_H
しかしこれはファイルの前後に書かないといけないという制約や、他のヘッダとトークン列が一致してしまうと意図せずヘッダがインクルードされないという問題がありました。
これに対してたった1行で書いて終わりの#pragma once
は、標準化を求める声も多く、目的が明確で、実装もあるにも関わらず、標準に入る気配すらありません。
twitterとかでもそういう声をたまに見るのですが、ちょっと考えれば難しそうだというのがわかってもらえるかと思うので、ここでまとめておこうと思います。
Boost.勉強会 #18 大阪
今日Boost.勉強会が開催されていたらしいので、そういう感じのタイトルにしておけばタイムリーかなって思いました。(小並感
さて、思い立ったがなんとやらという言葉がありますが、思い立ったので秩父神社まで日帰りで行ってきました。 予てより八意思兼命を祀っている秩父神社には参拝したいと思っていたところ、友人が(秩父神社ではないが)御朱印帳を取り出して見せてくれたりしたので参拝意欲が俄然高まってしまった。
ということで池袋から西武で一路秩父へ。
飯能から先、横瀬までの間の峡谷風景がとても良かった。
まだ横瀬だというのに、やたらテンションが高くなってしまったのがTLにいたようだ(なお一人旅)。
@Flast_RO あ~心がボソンジャンプするんじゃ~
— ろんず@今年は攻めの姿勢 (@athlonz) 2015年10月10日
西武秩父から秩父神社は十分歩ける距離らしかったので、歩いて街の景観を楽しんでいたのだが、やはり
@Flast_RO 跳躍
— ろんず@今年は攻めの姿勢 (@athlonz) 2015年10月10日
ということで歩くこと7分程度、ようやくたどり着いた。
— ろんず@今年は攻めの姿勢 (@athlonz) 2015年10月10日
あまり神社仏閣を写真でぱしゃぱしゃするのは好きではないので、一通り見て回って最後に御朱印を頂いてきた。
知恵の神だからだろうか、帰りの電車内でコードを書いたがそれなりのシンチョクは得られたように思う。
帰りがけには地酒を数本買い、またいつか来ようと思った。 次はもっと時間に余裕を持って(泊まるぐらいの勢いで)横瀬の手前でも途中下車したいと思った。
池袋に降りた時、俗世へと戻ってきてしまった後悔が若干あった。。。
futureで欲しいutility
つらつらとfutureを使ってたらこういうのが欲しいというのがあったのでまとめ。
と言っても2つしか無いけど
(static_)future_cast
future<T>
のcastが欲しいという話。std::(static|dynamic|const)_pointer_cast
があるんだからfutureも欲しくないですか?っていう感じで。
http://melpon.org/wandbox/permlink/IXRr02x2RP8k3FVd
こういう感じの物が稀に欲しくなるときがあって、まぁ普通にgetしてcastすればいいんだけど、先のコード例みたいにpolymorphicなオブジェクトを受け渡したい時に、I/Fを限定できるのでABIとか保存しやすいのではないかという感じ。
C++11/14で書くにはdeferred async使ってやればいいけど、future::then
が来たらそれで実装してもいいのかもしれない。
future::then
自体は提案とか読んでたりしてないからdeferredなのかasyncなのか、既にreadyでかつasyncなfutureをthenした時どこで走るのかとかそういうことを考え始めると困るかもしれない。
標準ライブラリの都合でMSVC12とかはとにかく酷いものになってるのでやめていただきたい。 C++14だと素直で良ても良い。
immediate
futureって未来に得られるかもしれない値を格納する感じのオブジェクトだけど、インターフェースとしてfutureを書かれると、「いや俺もう値持ってるし」みたいなときに(futureに直接値を仕込めないから)面倒で、じゃぁオーバーロードかー?というのもなんかなぁとなるので、即値をfutureでくるんでやるものが欲しい。
http://melpon.org/wandbox/permlink/ySucdA6uAo6BRKCu
実装としてはpromiseを使えば確かにできるんだけど、これshared stateをMT-safeにするオーバーヘッドが入るので、標準ライブラリの実装としてはMT-safeである必要はないようにもできるかもしれない(shared_futureは今のところ考えてなかったから問題はあるかもだけど)。
MSVC(に同梱されているcl.exe)のTwo-phase name lookupが未実装というのはどういう挙動をするのかという備忘録
Boost.勉強会の立ち話で id:redboltz さんからMSVCのTPLが未実装ということについて、詳細を聞いたので確かめてみた。
まぁ聞いたら話は簡単で、non-dependent typeであってもlookupがinstantiation timingまで遅れてしまうという感じ。
正しいTwo-phase name lookupの挙動は以下の様になる。
これをMSVC12に持ってくとこうなる
http://gyazo.flast.jp/6946ae3e7b533ce2ab610c5766789249.png
はー、なるほどね、たいへんだー
さて、VC14のCTPを出し始める頃にTwo-phase name lookupが新機能の予定に入っていてやっとか...となったわけですが、そのVC14のRCだとどうなるのかというと
http://gyazo.flast.jp/95b8c4057b8e0b0b7f50bcd0ca60d7bf.png
アッ、ハイ、
P.S. f*ck
Boost.Fusion 1.58 updates
Boost.Fusion 1.58は頑張ったし、Damien Buhlも頑張ったのでそれなりな更新がいくつかあります。 まだBeta出てない*1けどそろそろmasterがcloseしてbugfixのみになるので機能としてはfixした感じ。
主な新機能
- GitHub PR #12 Fusionのシーケンスを
boost::hash
で使えるように - GitHub PR #51
std::reference_wrapper
をサポート std::tuple
のサポート- GitHub PR #54 Fusionアダプタでの暗黙的な型推論をサポート
- ticket 9813, GitHub PR #14, GitHub PR #23, GitHub PR #26, GitHub PR #58 C++11/14 constexprのサポート
- いくつかのresult_ofをSFINAE-friendlyに
- ticket 10443
fusion::result_of::invoke
- GitHub PR #35
fusion::result_of::copy
fusion::result_of::move
fusion::result_of::swap
- GitHub PR #41
fusion::result_of::at_c
fusion::result_of::at
- ticket 10443
boost::hashのサポート
これまではFusionシーケンスは boost::hash
をサポートしていなかったので、Unordered Associative Containerに投げることができませんでした。
今回、新たに hash.hpp
が導入され、Boost.UnorderedへFusionシーケンスを投げることが出来るようになりました。
これはForward Sequenceであれば受け付けるので、アダプトしたシーケンスにも使えます。
#include <boost/unordered_set.hpp> #include <boost/fusion/include/vector.hpp> #include <boost/fusion/include/make_vector.hpp> #include <boost/fusion/include/equal_to.hpp> #include <boost/fusion/include/hash.hpp> // new int main() { boost::unordered_set<boost::fusion::vector<int>> m; m.insert(boost::fusion::make_vector(0)); m.insert(boost::fusion::make_vector(1)); }
今のところ、std::hash
は特殊化されていないので、std::unordered_{multi,}{map,set}
には直接使えませんが、boost::hash
を渡すことで同様のことが出来るようになります。
#include <unordered_set> #include <boost/fusion/include/vector.hpp> #include <boost/fusion/include/make_vector.hpp> #include <boost/fusion/include/equal_to.hpp> #include <boost/fusion/include/hash.hpp> // new int main() { std::unordered_set<boost::fusion::vector<int>, boost::hash<boost::fusion::vector<int>>> m; m.insert(boost::fusion::make_vector(0)); m.insert(boost::fusion::make_vector(1)); }
1.59には入れたいと思います。
std::reference_wrapper
boost::reference_wrapper
は前々から渡されたら通常の参照に展開するようになっていたんだけど、今回std::reference_wrapper
もそうなるようになった。
#include <functional> #include <cassert> #include <boost/fusion/include/vector.hpp> #include <boost/fusion/include/make_vector.hpp> #include <boost/fusion/include/at_c.hpp> int main() { int i = 0; auto v = boost::fusion::make_vector(std::ref(i)); boost::fusion::at_c<0>(v) = 1; }
reference_wrapper
のままでもええやんって思うかもだけど、reference_wrapper
のまま格納されると上のコードはコンパイルできない。
std::tuple
std::tuple
のサポートは実は前々から存在してはいたんだけど、ドキュメントが無かったり、一分実装が抜けていたりした。
今回ドキュメントを用意したし、大体実装されているはず。
いくつかのresult_ofをSFINAE-friendlyに
いくつかというのがミソ。1.59には全部をSFINAE-friendlyにしたい
アダプタでの暗黙的な型推論をサポート
これまでは構造体をアダプトするには型を書かないといけませんでした。
#include <boost/fusion/include/adapt_struct.hpp> #include <boost/fusion/include/at_c.hpp> namespace foo { namespace very_very_cool_namespace { typedef int how_quite_greatest_awesome_type; } struct bar { very_very_cool_namespace::how_quite_greatest_awesome_type hoge; very_very_cool_namespace::how_quite_greatest_awesome_type fuga; }; } BOOST_FUSION_ADAPT_STRUCT( foo::bar, (foo::very_very_cool_namespace::how_quite_greatest_awesome_type, hoge) (foo::very_very_cool_namespace::how_quite_greatest_awesome_type, fuga) ) int main() { foo::bar x = { 0 }; boost::fusion::at_c<0>(x) = 0xdeadbeef; }
very_very_cool_namespace::how_quite_greatest_awesome_type
を書くのは非常にだるいですし、構造体の変更に対して柔軟に対応できません。
一応これまでであっても型名の代わりにBOOST_FUSION_ADAPT_AUTO
を使えばBoost.TypeOfでの推論を使用できていましたが、依然として書かないといけないのは面倒です。
今回、Damienが頑張ってプリプロセッサしたところ、Variadic Macrosをサポートした環境では更に省略出来るようになりました。
#include <boost/fusion/include/adapt_struct.hpp> #include <boost/fusion/include/at_c.hpp> namespace foo { namespace very_very_cool_namespace { typedef int how_quite_greatest_awesome_type; } struct bar { very_very_cool_namespace::how_quite_greatest_awesome_type hoge; very_very_cool_namespace::how_quite_greatest_awesome_type fuga; }; } BOOST_FUSION_ADAPT_STRUCT( foo::bar, hoge, fuga ) int main() { foo::bar x = { 0 }; boost::fusion::at_c<0>(x) = 0xdeadbeef; }
C++11/14 constexprのサポート
#include <boost/fusion/include/vector.hpp> #include <boost/fusion/include/make_vector.hpp> #include <boost/fusion/include/at_c.hpp> int main() { constexpr auto v = boost::fusion::make_vector("foo", 0xdeadbeef); static_assert(boost::fusion::at_c<1>(v) == 0xdeadbeef, "Sadly, beef is daed ..."); }
見たまんまですね。これで不幸にも実行ができなくなってしまった環境であってもコンパイル時に計算できるので安心ですね。
C++14なら基本的にconstexprになってるはずです。C++11だといくつかがまだ対応出来てないです。少しずつなんとかしたいですね。
*1:3/11予定