title: how to map parse result with optional parts to a vector of variants?
body: <p>i need to convert an old hierarchical query system parser to C++
  my first idea was to port it 1:1 to C++ using Spirit</p>
  <p>beware:
  most of the example-code on the bottom is my rule-test code - to adapt the old syntax,
  the rules are worked out and doing what i want and my test-queries getting parsed by the rules - nice!</p>
  <p>but i have no idea how to port that to a qi:grammar based parser that spits out a vector of variants with the descent types i need from the query (with mandatory and partially optional parts)</p>
  <p>can anyone give me an advice how to do the mapping? i think i need some BOOST_FUSION_ADAPT_STRUCT adaptors to fill my result-vector</p>
  <p>the #if USE_GRAMMAR() code is not compilable - more or less a frame for your tips</p>
  <pre><code>// #define BOOST_SPIRIT_DEBUG
  #include &lt;boost/fusion/include/std_pair.hpp&gt;
  #include &lt;boost/spirit/include/qi.hpp&gt;
  #include &lt;iomanip&gt;
  #include &lt;map&gt;
  #include &lt;optional&gt;
  #include &lt;variant&gt;
  
  namespace qi = boost::spirit::qi;
  
  // these are my result-variant types
  
  struct Member{ std::string name; };
  struct Subscription{ std::size_t indice; };
  using Class_list = std::vector&lt;std::string&gt;;
  
  struct Instance_id{
      std::string class_name;
      std::string instance_name;
  };
  using Instance_list = std::vector&lt;Instance_id&gt;;
  
  struct Deep_search{ std::optional&lt;int&gt; max_depth; };
  
  struct Property_filter{};
  struct Parent{};
  struct Self{};
  struct Child{};
  
  using Value = std::variant&lt;Member, Class_list, Instance_list, Deep_search, Subscription, Property_filter, Parent, Self, Child&gt;;
  using Result = std::vector&lt;Value&gt;;
  
  // code that should use the qi::grammar parser
  // set that true and get a bunch of compile-errors :)
  #define USE_GRAMMAR() ( false )
  
  #if USE_GRAMMAR()
  template &lt;typename It&gt;
  struct Query_parser : qi::grammar&lt;It, Result()&gt;
  {
      Query_parser() : Query_parser::base_type( start ){
          using namespace qi;
  
          start = skip( space )[*query];
  
          // copy of the test rules from bottom
          identifier = qi::char_( &quot;a-zA-Z_&quot; ) &gt;&gt; *qi::char_( &quot;a-zA-Z0-9_&quot; );
          subscription = '[' &gt;&gt; qi::uint_ &gt;&gt; ']';
          member = identifier &gt;&gt; -subscription;
          class_list = '%' &gt;&gt; ( identifier | '(' &gt;&gt; -( identifier % ',' ) &gt;&gt; ')' );
          instance_id = identifier &gt;&gt; ':' &gt;&gt; identifier;
          instance_list = qi::skip( qi::blank )['#' &gt;&gt; ( instance_id | '(' &gt;&gt; -( instance_id % ',' ) &gt;&gt; ')' )];
          instance_or_class_list = class_list | instance_list;
          instance_or_class_list_filter = instance_or_class_list &gt;&gt; -subscription;
          property_filter = qi::char_( &quot;!&quot; ) &gt;&gt; '(' &gt;&gt; ')';
          deep_search = &quot;?&quot; &gt;&gt; -( '(' &gt;&gt; qi::uint_ &gt;&gt; ')' ) &gt;&gt; instance_or_class_list &gt;&gt; -property_filter &gt;&gt; -subscription;
          parent = &quot;..&quot;;
          self = &quot;.&quot;;
          child = &quot;/&quot;;
          query_part = ( member | child | parent | self | deep_search | instance_or_class_list_filter );
          query = query_part &gt;&gt; *( child &gt;&gt; *query_part );
      }
  
  private:
      qi::rule&lt;It, Result()&gt; start;
      // i don't know how to map the values in to the Result vector
      qi::rule&lt;It, char const*&gt; identifier; // -&gt; only a rule build helper
      qi::rule&lt;It, char const*&gt; subscription; // output
      qi::rule&lt;It, char const*&gt; member; // output
      qi::rule&lt;It, char const*&gt; class_list; // output
      qi::rule&lt;It, char const*&gt; instance_id;
      qi::rule&lt;It, char const*&gt; instance_list; // output
      qi::rule&lt;It, char const*&gt; instance_or_class_list;
      qi::rule&lt;It, char const*&gt; instance_or_class_list_filter;
      qi::rule&lt;It, char const*&gt; property_filter; // output
      qi::rule&lt;It, char const*&gt; deep_search; // output
      qi::rule&lt;It, char const*&gt; parent; // output
      qi::rule&lt;It, char const*&gt; self; // output
      qi::rule&lt;It, char const*&gt; child; // output
      qi::rule&lt;It, char const*&gt; query; // output
      qi::rule&lt;It, char const*&gt; query_part; // -&gt; only a rule build helper
  };
  #endif
  
  template &lt;typename P&gt;
  bool test_parser( char const* input, P const&amp; p, bool full_match = true ){
      using boost::spirit::qi::parse;
      char const* f( input );
      char const* l( f + strlen( f ) );
      return parse( f, l, p ) &amp;&amp; ( !full_match || ( f == l ) );
  }
  
  int main()
  {
  #if USE_GRAMMAR()
      using It = std::string::const_iterator;
      Query_parser&lt;It&gt; const p;
  
      for( std::string const&amp; input : { &quot;ube/../abc/abc[2]/?(3)#(A:a,B:b)!()[2]/blub[2]/test/?%A&quot; } ){
          It f = input.begin(), l = input.end();
          Result data;
          bool ok = parse( f, l, p, data );
  
          if( ok ){
              std::cout &lt;&lt; &quot;Parse o\n&quot;;
          }
          else{
              std::cout &lt;&lt; &quot;Parse failed\n&quot;;
          }
  
          if( f != l )
              std::cout &lt;&lt; &quot;Remaining unparsed: &quot; &lt;&lt; std::quoted( std::string( f, l ) ) &lt;&lt; &quot;\n&quot;;
      }
  
      int brk = 1;
  
  #else
      // my working rule tests to get a feeling what i try to reach
  
      // identifier
      qi::rule&lt;char const*&gt; identifier;
      identifier = qi::char_( &quot;a-zA-Z_&quot; ) &gt;&gt; *qi::char_( &quot;a-zA-Z0-9_&quot; );
      assert( test_parser( &quot;_a_b4&quot;, identifier ) );
  
      // subcription
      qi::rule&lt;char const*&gt; subscription;
      subscription = '[' &gt;&gt; qi::uint_ &gt;&gt; ']';
      assert( test_parser( &quot;[2]&quot;, subscription ) );
      assert( test_parser( &quot;[45]&quot;, subscription ) );
  
      // member
      qi::rule&lt;char const*&gt; member;
      member = identifier &gt;&gt; -subscription;
      assert( test_parser( &quot;abc&quot;, member ) );
      assert( test_parser( &quot;abc[2]&quot;, member ) );
  
      // class list
      qi::rule&lt;char const*&gt; class_list;
      class_list = '%' &gt;&gt; ( identifier | '(' &gt;&gt; -( identifier % ',' ) &gt;&gt; ')' );
      assert( test_parser( &quot;%A&quot;, class_list ) );       // vector&lt;{{class_name}}&gt; size 1
      assert( test_parser( &quot;%(A,B,C)&quot;, class_list ) ); // vector&lt;{{class_name},{},...}&gt; size n
  
      // instance id
      qi::rule&lt;char const*&gt; instance_id;
      instance_id = identifier &gt;&gt; ':' &gt;&gt; identifier;
      assert( test_parser( &quot;_a_b4:blub&quot;, instance_id ) );
  
      // instance list
      qi::rule&lt;char const*&gt; instance_list;
      instance_list = qi::skip( qi::blank )['#' &gt;&gt; ( instance_id | '(' &gt;&gt; -( instance_id % ',' ) &gt;&gt; ')' )];
      assert( test_parser( &quot;#a:A&quot;, instance_list ) );       // vector&lt;{{class_name, instance_name}}&gt; size 1
      assert( test_parser( &quot;#(a:A,b:B)&quot;, instance_list ) ); // vector&lt;{{class_name, instance_name},{},...}&gt; size n
  
      // combined class/instance-list
      qi::rule&lt;char const*&gt; instance_or_class_list;
      instance_or_class_list = class_list | instance_list;
      assert( test_parser( &quot;#(a:A,b:B)&quot;, instance_or_class_list ) );
      assert( test_parser( &quot;%(A,B,C)&quot;, instance_or_class_list ) );
  
      qi::rule&lt;char const*&gt; instance_or_class_list_filter;
      instance_or_class_list_filter = instance_or_class_list &gt;&gt; -subscription;
      assert( test_parser( &quot;#(a:A,b:B)[2]&quot;, instance_or_class_list_filter ) );
      assert( test_parser( &quot;%(A,B,C)[5]&quot;, instance_or_class_list_filter ) );
  
      // expression - dummy
      qi::rule&lt;char const*&gt; property_filter;
      property_filter = qi::char_( &quot;!&quot; ) &gt;&gt; '(' &gt;&gt; ')';
  
      // deep search
      qi::rule&lt;char const*&gt; deep_search;
      deep_search = &quot;?&quot; &gt;&gt; -( '(' &gt;&gt; qi::uint_ &gt;&gt; ')' ) &gt;&gt; instance_or_class_list &gt;&gt; -property_filter &gt;&gt; -subscription;
      assert( test_parser( &quot;?%ABC&quot;, deep_search ) );
      assert( test_parser( &quot;?%ABC[2]&quot;, deep_search ) );
      assert( test_parser( &quot;?%(A,B,C)&quot;, deep_search ) );
      assert( test_parser( &quot;?%(A,B,C)[2]&quot;, deep_search ) );
      assert( test_parser( &quot;?#ABC:EFG&quot;, deep_search ) );
      assert( test_parser( &quot;?#(A:a,B:b,C:c)&quot;, deep_search ) );
      assert( test_parser( &quot;?(2)%blub!()[2]&quot;, deep_search ) );
  
      // goto parent
      qi::rule&lt;char const*&gt; parent;
      parent = &quot;..&quot;;
      assert( test_parser( &quot;..&quot;, parent ) );
  
      // stay
      qi::rule&lt;char const*&gt; self; // um im Root zu suchen
      self = &quot;.&quot;;
      assert( test_parser( &quot;.&quot;, self ) );
  
      // member or root
      qi::rule&lt;char const*&gt; child; // or root
      child = &quot;/&quot;;
      assert( test_parser( &quot;/&quot;, child ) );
  
      // complete query
      qi::rule&lt;char const*&gt; query;
      qi::rule&lt;char const*&gt; query_part;
      query_part = ( member | child | parent | self | deep_search | instance_or_class_list_filter );
      query = query_part &gt;&gt; *( child &gt;&gt; *query_part );
  
      assert( test_parser( &quot;#(A:a,B:b)[2]&quot;, query ) );
      assert( test_parser( &quot;abc/..&quot;, query ) );
      assert( test_parser( &quot;abc/.&quot;, query ) );
      assert( test_parser( &quot;..&quot;, query ) );
      assert( test_parser( &quot;.&quot;, query ) );
      assert( test_parser( &quot;../&quot;, query ) );
      assert( test_parser( &quot;./&quot;, query ) );
      assert( test_parser( &quot;abc&quot;, query ) );
      assert( test_parser( &quot;ube/../abc/abc[2]/?(3)#(A:a,B:b)!()[2]/blub[2]/test/?%A&quot;, query ) );
      assert( test_parser( &quot;abc[2]&quot;, query ) );
      assert( test_parser( &quot;/&quot;, query ) );
      assert( test_parser( &quot;?(2)%ABC&quot;, query ) );
      assert( test_parser( &quot;?(2)%(ABC)!()[2]&quot;, query ) );
      assert( test_parser( &quot;abc[2]&quot;, query ) );
      assert( test_parser( &quot;abc/?(2)%Class[2]&quot;, query ) );
      assert( test_parser( &quot;?(2)%ABC&quot;, query ) );
  
      /*
          &quot;ube/../abc/abc[2]/?(3)#(A:a,B:b)!()[2]/blub[2]/test/?%A&quot;
          
          should give a Result Value vector of
  
          {
              Member, 
              Child, 
              Parent, 
              Child, 
              Member, 
              Child, 
              Member,
              Subcription, 
              Child
              Deep_search, 
              Instance_list, 
              Property_filter, 
              Subscription, 
              Child
              Member, 
              Subcription,
              Child, 
              Member, 
              Child, 
              Deep_search,
              Class_list  
          }
      */
  
  #endif
  
      return 0;
  }
  </code></pre>
  <p>thanks for any advice</p>
  <p><strong>UPDATE</strong></p>
  <p>i tried to extend sehe's example replacing the Query with a struct with rooted bool and a path parts vector</p>
  <pre><code># changed Ast::Query
  using Parts = std::vector&lt;Part&gt;;
  struct Query
  {
      bool rooted{};
      Parts parts;
  };
  
  # another adapter
  BOOST_FUSION_ADAPT_STRUCT( AST::Query, rooted, parts )
  
  # two new rules
  qi::rule&lt;It, AST::Parts()&gt; parts;
  qi::rule&lt;It, bool()&gt; rooted;
  
  # rule definition
  parts           = part % '/';
  rooted          = qi::matches[&quot;/&quot;];
  query           = rooted &gt;&gt; parts;
  </code></pre>
  <p>and changed the debug printers accordingly
  but i always get a compilation error somewhere in boost\boost\spirit\home\support\container.hpp</p>
  <pre><code>//[customization_container_value_default
  template &lt;typename Container, typename Enable/* = void*/&gt;
  struct container_value
    : detail::remove_value_const&lt;typename Container::value_type&gt;
  {};
  </code></pre>
  <p><a href="https://coliru.stacked-crooked.com/a/e510dcc472e5e5ea" rel="nofollow noreferrer">Live On Coliru</a>
  (if the execution time doesn't exceed the limit)</p>