$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [Boost-users] Can boost help me organize/parse lots of binary data?
From: Antony Polukhin (antoshkka_at_[hidden])
Date: 2013-02-22 01:16:40
2013/2/21 Larry Evans <cppljevans_at_[hidden]>:
> I haven't a clear idea how this would work because I assumed that
> the binary input stream would have to have something that
> 1st would be decoded into the tag for the variant.
> Then, if your variant visitor solution is used, some
> code (not shown) would create some default constructed value for
> the bounded type corresponding to that tag and then call the visitor.
>
> All the above is just off the top of my head, but, as I said,
> I'm not real sure the variant visitor solution would work.
>
> Could you provide more pseudo code to clarify.
Here is some more pseudo code, may be it will help you.
#include <boost/variant.hpp>
struct name_visitor: public boost::static_visitor<std::string> {
template <class T>
const std::string& opertor()(const T& val) const {
    return val.name;
}
// Specific visitor for Person
std::string opertor()(const Person& val) const {
    return val.first_name + " " + val.second_name;
}
// Specific visitor for Something
std::string opertor()(const Something& val) const {
    throw std::logic_error("Class Something has no name!");
}
};
  class EmployeePacket
   {
     typedef boost::variant<String, Double, Person, Something> variant_t;
     std::vector<variant_t> Items;
     EmployeePacket()
     {
           // copying variants is not as fast as copying pointers,
           // so it is better to reserve some space first
           Items.reserve(200);
      }
     void Decode(istream& Stream)
     {
       while (Stream) {
           switch (Stream.getc()) {
           case 'S': Items.push_back(String(Stream)); break;
           case 'D': Items.push_back(Double(Stream)); break;
           case 'P': Items.push_back(Person(Stream)); break;
           }
       }
     }
     double GetSalary(std::size_t index) const
     {
       // Will throw if at 'index' is not a Double type
       return boost::get<Double>(Items[index]).value;
     }
     std::string GetName(std::size_t index) const {
         return boost::apply_visitor(name_visitor(), Items[index]);
     }
   }
// All the folloving classes must have a constructor that accepts an istream&
 class Double
 {
   string name;
   string units;
 //  double decode_conversion_scale;
 //  double decode_conversion_translate;
 //  unsigned number_of_bits_used_to_encode
 //  double scale_factor
   double value;
   void Decode(istream& Stream) // Will be called from constructor
    {
     Stream.read(&value, 8);
     value = value * decode_conversion_scale + decode_conversion_translate;
  }
   class String
   {
     string name;
     string value;
     void Decode(istream& Stream); // Will be called from constructor
   }
class Person
   {
     string first_name;
     string second_name;
     void Decode(istream& Stream); // Will be called from constructor
   }
class Something
   {
     /*string name; Has NO name! */
     void Decode(istream& Stream);
   }
Forgot to mention about disadvantages:
* slower copy construction and copy assignment of variant types
(compared to pointers)
* all the types used in variant must be full (not just forward declared)
If second disadvantage is 'too disadvantageous' for you, I can provide
exactly the same example with boost::any instead of boost::variant
-- Best regards, Antony Polukhin