4

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?

Dave Schweisguth
  • 36,475
  • 10
  • 98
  • 121
Haitham Gad
  • 1,529
  • 2
  • 13
  • 23
  • Will this really compile? you are using the type `sexpr` while defining the type itself. – Some programmer dude Jul 30 '12 at 06:16
  • I was just trying to minimize the code to demonstrate my point. I edited the code to show what I really have. This is still minimized though. You can think of sexpr as a wrapper to node_type that forwards apply_visitor() requests to the underlying recursive variant (`node`). – Haitham Gad Jul 30 '12 at 07:14

1 Answers1

3

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_;
}
Xeo
  • 129,499
  • 52
  • 291
  • 397
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • I usually just create transformation visitor that copies nodes or returns the modified one. I know it could be inefficient, but expressiveness and maintainability come first. Solve perf problems when you have prove you have them (in which case, you might just rewrite the logic or not use variant etc.) – sehe Feb 14 '16 at 22:09