Parsing vectors of shared_ptr to base class

Mario Lang <[email protected]>
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
Hi.

I just realized I can parse heterogenous containers of pointers to base
classes with something like this:

#if !defined(BMML_SPIRIT_X3_HPP)
#define BMML_SPIRIT_X3_HPP

#include <boost/spirit/home/x3.hpp>

namespace bmml {
  namespace spirit {
    inline namespace x3 {
      template<typename T>
      struct dynamic_pointer_parser : boost::spirit::x3::parser<
        dynamic_pointer_parser<T>
      > {
        using attribute_type = std::shared_ptr<T>;
        template < typename Iterator, typename Context, typename RContext
                 , typename Attribute>
        bool parse( Iterator& first, Iterator const& last
                  , Context const& context, RContext& rcontext
                  , Attribute& attr) const {
          if (auto val = std::dynamic_pointer_cast<T>(*first)) {
            boost::spirit::x3::traits::move_to(val, attr);
            ++first;

            return true;
          }

          return false;
        }
      };

      template <typename T> dynamic_pointer_parser<T> shared_ptr = {};
    }
  }
}

#endif // !defined(BMML_SPIRIT_X3_HPP)

A small use case might look like this:

#include <fstream>
#include <iostream>
#include <x3.hpp>
#include <bmml.hxx>

using std::begin;
using std::cout;
using bmml::dom::element;
using std::end;
using std::endl;
using bmml::generic_text;
using std::ifstream;
using bmml::newline;
using bmml::spirit::shared_ptr;
using bmml::space;
using std::vector;
namespace x3 = boost::spirit::x3;

int main(int argc, char *argv[]) {
  ifstream file(argv[1]);
  auto score = bmml::parse(file, argv[1]);
  if (auto score_data = score->data()) {
    vector<std::shared_ptr<element>> text;
    auto iter = begin(*score_data);
    if (x3::parse(iter, end(*score_data),
              *(shared_ptr<space> | shared_ptr<newline> | shared_ptr<generic_text>),
              text)) {
      cout << text.size() << " text elements at beginning." << endl;
    }
  }
}

This is going to save me a lot of icky nested conditionals and casts.
And has quite some potential.  I am going to use it a lot with operator%
to parse a nested vector of things separated by specific spearators.
Something I wouldn't want to write with imperative code.
But with this wrapping, spirit can do all the magic.

I wonder if this could be made generic enough to be put into X3 / if
something like this would be useful to others?

Any suggestions for better naming?  I wonder if attribute_type can be
defined properly?
decltype(std::dynamic_pointer_cast<T>(*std::declval<Iterator>())) can
not work because Iterator is not known.

Besides, it does all what I want already.  I can parse casted pointers
into adapted structs, and it will happily do the right thing if
operator| is used on a vector of shared_ptr to a common base.

-- 
CYa,
  ⡍⠁⠗⠊⠕

------------------------------------------------------------------------------
Transform Data into Opportunity.
Accelerate data analysis in your applications with
Intel Data Analytics Acceleration Library.
Click to learn more.
http://pubads.g.doubleclick.net/gampad/clk?id=278785231&iu=/4140
_______________________________________________
Spirit-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spirit-general
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.