にゃははー

はへらー

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のconst int &ってなんですかねぇ... prvalueですよ渡したのは...
で、何が問題かっていうと、

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とはならないのです。
やたー