Boost.Peroperoぷろとー ちがった... Boost.Protoぺろぺろー
最近自分の研究でProto充してSFINAEで脳汁噴出してるんだけど、domainとExtendsを作ってgeneratorってなんぞやーって適当に書いてればよかったんだ。
けど、P-Stade.Ovenのregularとかそこら辺でもよく出てるprvalueをexpressionに持ってくるとDangling Pointerになってしまううがーってなってしまうわけです。
流石に解決されてるはずだと思っていろいろReferenceを読みあさって見つけました。
つまり普通にこんな感じで
struct expression : proto::or_< proto::terminate<...> ... template <typename> struct Extends; struct domain : proto::domain<proto::generator<Extends>, expression> {};
とか書くわけですよ。
で、これで適当にET(例えば proto::lit(1)+1 とか)を構築すると次のようになると思います。(かなり端折ってます
expression< proto::expr_< proto::tag::plus , proto::terminate<const int &> , proto::terminate<const int &> > >
ところでproto::terminate
で、何が問題かっていうと、
thread th( proto::lit(1)+1 );
とかスレッドとかに投げるとどうなりますか!
これはdangling pointerを指すことになるので死にますね...ってことです。
で、これを解決するのがdomainの定義の仕方でした。
さっきは proto::generator にExtendsを渡してADLで拾ってくれるようにしたわけですが、protoのgeneratorにはproto::by_value_generatorという名前まんまの物があります。
これ普通に使うの難しい(私はうまくいかなかった)んですが、こいつはtemplate classでは無いのでExtendsを投げることができないのです。
オワタ って思うのは早計で、その下を少し読んでくとproto::compose_generatorsというのがあります。こいつはgeneratorを2つ受け取って順に適用させるものです。
こいつだ!
ってことで解は
struct domain
: proto::domain<
proto::compose_generators<
proto::by_value_generator
, proto::generator<Extends>
>
, expression
> {};
となるのです。こうすることで
expression< proto::expr_< proto::tag::plus , proto::terminate<int> , proto::terminate<int> > >
とめでたくなります。functorとかもCopyConstructible/CopyAssignableであればコピーしてくれるのでスレッドに投げてもDangling Pointerとはならないのです。
やたー