c++ - cannot construct std::string from placeholder in Boost.Spirit -


i have started working on boost.spirit based simple parser parse c++-like file (the c++-ish part built-in template types; e.g. map<string, smart_ptr<int>> name_object_map; - built-in compiler, , user cannot declare template classes). nevertheless, grammar intended contain data structure declarations, , not expressions, except constant expressions used initialization of enumerator declarations; enum e { = 4 * 5 + 3 }; valid. not problem me, because couldn't parse e way want yet :)

i have made following yesterday, after reading docs , examples, doesn't compile:

#include <boost/spirit/include/phoenix.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/qi_char_class.hpp> #include <cassert> #include <memory> #include <string> #include <utility>  struct context {};  class foo {   std::string name;   const context *ctx;  public:   foo(const std::string &name, const context *ctx) : name(name), ctx(ctx) {} };  using foo_ref = std::shared_ptr<foo>;  template <typename iterator> struct skipper : boost::spirit::qi::grammar<iterator> {   skipper() : skipper::base_type(start) {     using namespace boost::spirit;     qi::char_type char_;     ascii::space_type space;      start = space                             // tab/space/cr/lf             | "/*" >> *(char_ - "*/") >> "*/" // c-style comments         ;   }    boost::spirit::qi::rule<iterator> start; };  template <typename iterator> struct the_parser : boost::spirit::qi::grammar<iterator, std::vector<foo_ref>(),                                                skipper<iterator>> {   the_parser() : the_parser::base_type(start), current_context(&root) {     using namespace boost::spirit;     namespace phx = boost::phoenix;      identifier = qi::lexeme[qi::alpha >> *qi::alnum];     start = *(foo_decl); // currently, no semantic action attached.                          // create root decl in ast.      foo_decl = (lit("foo") >> identifier)[qi::_val = std::make_shared<foo>(                                                qi::_1, current_context)] >>                qi::char_('{') >> qi::char_('}') >> qi::char_(';');     boost_spirit_debug_nodes((identifier)(start)(foo_decl));   }   boost::spirit::qi::rule<iterator, std::string(), skipper<iterator>>       identifier;   boost::spirit::qi::rule<iterator, std::vector<foo_ref>(), skipper<iterator>>       start;   boost::spirit::qi::rule<iterator, foo_ref(), skipper<iterator>> foo_decl;   context root;   const context *current_context; };  int main() {   the_parser<std::string::const_iterator> parser;   std::vector<foo_ref> root;    const std::string content = "foo john_doe { };";   auto first = content.cbegin(), last = content.cend();   bool r = boost::spirit::qi::phrase_parse(       first, last, parser, skipper<std::string::const_iterator>(), root);   assert(r && first == last); } 

compiling clang on mac (the first line std::make_shared):

error: no matching constructor initialization of 'foo'           __second_(_vstd::forward<_args2>(_vstd::get<_i2>(__second_args))...)           ^         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ... note: candidate constructor not viable: no known conversion 'const boost::phoenix::actor<boost::spirit::argument<0> >' 'const std::string' (aka   'const basic_string<char, char_traits<char>, allocator<char> >') 1st argument   foo(const std::string &name, const context *ctx) : name(name), ctx(ctx) {}   ^ 

in foo_decls semantic action, cannot construct foo (through std::make_shared), because first attribute's result cannot converted std::string. however, if add class member std::string s, , instead, works:

foo_decl = (lit("foo") >> identifier)[boost::phoenix::ref(s) = qi::_1] >>                  qi::char_('{') >> qi::char_('}') >> qi::char_(';'); 

likewise, if try std::cout it, can see john_doe printed.

if bind member function call phoenix, works:

foo_decl = (lit("foo") >> identifier)[qi::_val =                    boost::phoenix::bind(&the_parser, this, qi::_1)] >>            qi::char_('{') >> qi::char_('}') >> qi::char_(';');  foo_ref make_foo(const std::string &n) {   return std::make_shared(n, current_context); } 

these last 3 workarounds mean there implicit conversion sequence decltype(qi::_1) std::string; isn't correct?

i happy, if show me mistake or gap in understanding of how semantic actions, , placeholders work. looks strange me why std::make_shared doesn't work.

thank you!

first of all:

using phoenix::function first link:

live on coliru

#define boost_spirit_debug #include <boost/spirit/include/phoenix.hpp> #include <boost/spirit/include/qi.hpp> #include <cassert> #include <memory> #include <string> #include <utility>  namespace {     template <typename t> struct make_shared_f {         template <typename... a> struct result { typedef std::shared_ptr<t> type; };          template <typename... a> typename result<a...>::type operator()(a &&... a) const {             return std::make_shared<t>(std::forward<a>(a)...);         }     };      template <typename t> using make_shared_ = boost::phoenix::function<make_shared_f<t> >; }  struct context {};  class foo {     std::string name;     const context *ctx;    public:     foo(const std::string &name, const context *ctx) : name(name), ctx(ctx) {} };  using foo_ref = std::shared_ptr<foo>;  template <typename iterator> struct skipper : boost::spirit::qi::grammar<iterator> {     skipper() : skipper::base_type(start) {         using namespace boost::spirit;         qi::char_type char_;         ascii::space_type space;          start = space                             // tab/space/cr/lf                 | "/*" >> *(char_ - "*/") >> "*/" // c-style comments             ;     }      boost::spirit::qi::rule<iterator> start; };  template <typename iterator> struct the_parser : boost::spirit::qi::grammar<iterator, std::vector<foo_ref>(), skipper<iterator> > {     the_parser() : the_parser::base_type(start), current_context(&root) {         using namespace boost::spirit;         namespace phx = boost::phoenix;          identifier = qi::alpha >> *qi::alnum;         // create root decl in ast.          foo_decl = ("foo" >> identifier) [qi::_val = make_shared_<foo>{}(qi::_1, current_context)] >>                    '{' >> '}' >> ';';          start      = *foo_decl; // currently, no semantic action attached.         boost_spirit_debug_nodes((identifier)(start)(foo_decl));     }     boost::spirit::qi::rule<iterator, std::string()> identifier;     boost::spirit::qi::rule<iterator, foo_ref(), skipper<iterator> > foo_decl;     boost::spirit::qi::rule<iterator, std::vector<foo_ref>(), skipper<iterator> > start;     context root;     const context *current_context; };  int main() {     the_parser<std::string::const_iterator> parser;     std::vector<foo_ref> root;      const std::string content = "foo johndoe { };";     auto first = content.cbegin(), last = content.cend();     bool r = boost::spirit::qi::phrase_parse(first, last, parser, skipper<std::string::const_iterator>(), root);     if (r)         std::cout << "success\n";     else         std::cout << "failed\n";      if (first != last)         std::cout << "remaining unparsed: '" << std::string(first,last) << "'\n";  } 

prints

success 

along debug output of

<start>   <try>foo johndoe { };</try>   <foo_decl>     <try>foo johndoe { };</try>     <identifier>       <try>johndoe { };</try>       <success> { };</success>       <attributes>[[j, o, h, n, d, o, e]]</attributes>     </identifier>     <success></success>     <attributes>[0x60600000ebb0]</attributes>   </foo_decl>   <foo_decl>     <try></try>     <fail/>   </foo_decl>   <success></success>   <attributes>[[0x60600000ebb0]]</attributes> </start> 

Comments

Popular posts from this blog

sequelize.js - Sequelize group by with association includes id -

android - Robolectric "INTERNET permission is required" -

java - Android raising EPERM (Operation not permitted) when attempting to send UDP packet after network connection -