1

I am using boost recursive variant to store the variant data which I want to encode using msgpack for which I need to get the raw data to pass into encode() function (see below).

I tried three different options in encode() function below but doesn't work. What are the alternates?

typedef std::vector<boost::recursive_variant_> vector_rvariant_t; 
typedef std::map<std::string, boost::recursive_variant_> map_rvariant_t;

typedef boost::make_recursive_variant <bool, boost::uint8_t, boost::uint32_t, 
        boost::int32_t, double, std::string, boost::uuids::uuid,  
        vector_rvariant_t, map_rvariant_t > ::type rvariant_type;

/**
 Wrapper class for boost::make_recuverise_variant<>::type
*/
class rvariant {
public:
   // encode the _data to msgpack buffer 
   //NEED HELP for this function.
    void encode(msgpack::sbuf& sbuf) {
       // msgpack::pack(sbuf, (*type_)data_);
       // msgpack::pack(sbuf, boost::get<typeid(data_)>(data_));
       // msgpack::pack(sbuf, boost::get<*type_>(data_));
    }

    // constructor 
    explicit template <typename T> rvariant(const T& data) {
       data_ = data;
       type_ =  (std::type_info*)&typeid(data);
    }

    // operator=  
   template <typename T> rvariant& operator=(const T& data) {
       data_ = data;
       type_ = (std::type_info*)&typeid(data);
       return *this;
   }

    // get the data 
   template<typename T> T get() {
       return boost::get< T >(data_);
   }

private:
  rvariant_type data_;
  std::type_info* type_;

};
rjoshi
  • 1,645
  • 1
  • 20
  • 31

1 Answers1

1

I don't think you're using std::type_info in a way that works with Boost::Variant.

Idea:

  1. Use the code similar to that provided here to wrap your calls to encode your own tag. By using a visitor, you'll essentially restrict yourself to the public interface of the Boost.Variant library. Alternative: use variant.which

  2. Don't try to piggy back off of boost::variant's internal tagging and data storage, since it might change later. Keep in mind that Boost.Variant may allocate its internal data differently based on compiler features and based the properties of the template parameters (e.g. reference types are treated specially). Instead, encode the tag separately (as in step one) and then encode the (typed) data separately.

I hope that helps. I guess the short version is this: your approach, while more direct than what I've described, is harder to get right because you're relying on the internals of Variant.

Edit: I had a look at the Boost.Serialization source. It might help: http://svn.boost.org/svn/boost/trunk/boost/serialization/variant.hpp

Edit: To illustrate (and to make the answer more self-contained), here is what the visitor in Boost.Serialization looks like (see link above):

template<class Archive>
struct variant_save_visitor : boost::static_visitor<>  {
  variant_save_visitor(Archive& ar) : m_ar(ar) {}

  template<class T>
  void operator()(T const & value) const {
    m_ar << BOOST_SERIALIZATION_NVP(value);
  }
private:
  Archive & m_ar;
};
Community
  • 1
  • 1
phooji
  • 10,086
  • 2
  • 38
  • 45
  • @phooji: Thx. When I try your static visitation, I get below error /home/rjoshi/trunk/vendor/opensource/boost/v1.45.0/include/boost/variant/variant.hpp:832: error: return-statement with a value, in function returning 'void' How are you suggesting to use variant.which? – rjoshi Mar 26 '11 at 14:36
  • @rjoshi: When you inherit from `boost::static_visitor`, all `operator()` overloads should have return type `SOMETYPE`. For `which`, have a closer look at the code in serialization/variant.hpp (link above). – phooji Mar 26 '11 at 14:57
  • @phooji: So basically I need to write static_visitor and overload function() for each possible conversion type. How about recursive vector and recursive map which are defines as typedef std::vector vector_rvariant_t; typedef std::map map_rvariant_t; – rjoshi Mar 26 '11 at 15:00
  • @rjoshi: Correct. For arbitrarily-large types, it depends on how msgpack works (I am not familiar with it). If it needs to know the size up front, then you can write a separate visitor that computes the size (recursively, by keeping a running total). If you do not need to record the size explicitly, then you just need a 'separator' in the data stream to help you reconstruct it later. Conceptually, this is similar to what data formats like JSON look like. – phooji Mar 26 '11 at 21:06
  • @phooji: msgpack doesn't need size and work with all primitive types and STL containers including list and map. Problem is I am lazy to write visitation for all data types and possible conversion so think if there was a way to directly typecast the variant data. But looks like no alternate. I will increment your answer and wait for if someone else provider what I am looking for. If not than will accept your answer :) . Thx. – rjoshi Mar 26 '11 at 23:15
  • @rjoshi: If msgpack already supports the types in your variant, then you can use tempplating to write just one method. Both the SO link and the Boost link show this. I'll add the Boost.Serialization visitor to the answer -- it is just 10 lines long. – phooji Mar 27 '11 at 00:12
  • @phooji: I implemented static vistor for all types defined in recursive variant still doesn't work. Compiler is not able to resolve the datatype of variant and gives error apply_visitor(variant_save_vistor, rvariant_type&) not defined. – rjoshi Mar 28 '11 at 05:33
  • @rjoshi: I'll need more detail than that. Please edit the question with your new approach or close this thread and ask it as a separate question. – phooji Mar 28 '11 at 05:37
  • @phooji: Infact it did work. Thx for the help. Problem is still for vector_variant_t and map_variant_t types. – rjoshi Mar 28 '11 at 11:52