Question

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?

Was it helpful?

Solution

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_;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top