質問

I have a recursive variant that models an S-expression:

   struct sexpr {
      typedef boost::variant<
         nil,
         int,
         double,
         symbol,
         string,
         boost::recursive_wrapper<list<sexpr> >
      > node_type;

      node_type node;
   };

I'd like the empty list to always be represented by nil (not list<sexpr>). However, I'm stuck with the implementation of the push_back() visitor. When the underlying type is nil, I'd like it to change that type to list<sexpr> and to push back the supplied value:

   struct push_back_visitor: public boost::static_visitor<void>
   {
      push_back_visitor(const sexpr &arg): arg_(arg) {}

      template <typename T>
      void operator()(const T &value) const {
         throw bad_visit();
      }

      void operator()(nil &val) const {
         // how to change the underlying type to list<sexpr> here?
         // lst.push_back(arg_);
      }

      void operator()(list<sexpr> &lst) const {
         lst.push_back(arg_);
      }

      sexpr arg_;
   };

Any ideas?

役に立ちましたか?

解決

boost::variant doesn't provide a mechanism to access the variant from within a visitor; however there's nothing to stop you from modifying or wrapping your visitor to carry a reference to the variant itself. Modifying the type of the variant from within a visitor visiting that variant is not mentioned in the documentation, but looks like it should be safe (since the variant visitor apply functions have to return as soon as the visitor is called).

template<typename Variant, typename Visitor>
struct carry_variant_visitor
  : public boost::static_visitor<typename Visitor::result_type>
{
    carry_variant_visitor(Variant &variant, Visitor visitor):
        variant_(variant), visitor_(visitor) { }
    template<typename T> 
    typename Visitor::result_type operator()(T &t) const {
        return visitor_(variant_, t);
    }
    Variant &variant_;
    Visitor visitor_;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top