c++ - making a vector of shared pointers from Spirit Qi -
this followup question a previous question.
i can parse vectors of strings grammar, cannot seem parse vector of shared pointers strings; i.e. std::vector<std::shared_ptr<std::string> >
, , need bit of help.
my compiling header:
#define boost_spirit_use_phoenix_v3 1 #include <boost/spirit/include/qi_core.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <iostream> #include <string> #include <boost/spirit/include/phoenix_stl.hpp> #include <boost/phoenix/bind/bind_member_function.hpp> #include <boost/spirit/include/phoenix_fusion.hpp> // solution lazy make shared comes forum, user sehe. // https://stackoverflow.com/questions/21516201/how-to-create-boost-phoenix-make-shared // post found using google search terms `phoenix construct shared_ptr` // changed boost::shared_ptr std::shared_ptr 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> >; } namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; template<typename iterator, typename skipper = ascii::space_type> struct systemparser : qi::grammar<iterator, std::vector<std::shared_ptr<std::string> >(), skipper> { systemparser() : systemparser::base_type(variable_group_) { namespace phx = boost::phoenix; using qi::_1; using qi::_val; using qi::eps; using qi::lit; var_counter = 0; declarative_symbols.add("variable_group",0); variable_group_ = "variable_group" > genericvargp_ > ';'; genericvargp_ = new_variable_ % ','; // new_variable_ = unencountered_symbol_ [_val = make_shared_<std::string>() (_1)]; unencountered_symbol_ = valid_variable_name_ - ( encountered_variables | declarative_symbols ); valid_variable_name_ = +qi::alpha >> *(qi::alnum | qi::char_("[]_") ); // debug(variable_group_); debug(unencountered_symbol_); debug(new_variable_); debug(genericvargp_); // boost_spirit_debug_nodes((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_)) } // rule declarations. these member variables parser. qi::rule<iterator, std::vector<std::shared_ptr<std::string> >(), skipper > variable_group_; qi::rule<iterator, std::vector<std::shared_ptr<std::string> >(), skipper > genericvargp_; qi::rule<iterator, std::shared_ptr<std::string()> > new_variable_; qi::rule<iterator, std::string()> unencountered_symbol_; qi::rule<iterator, std::string()> valid_variable_name_; unsigned var_counter; qi::symbols<char,int> encountered_variables; qi::symbols<char,int> declarative_symbols; };
with driver code:
int main(int argc, char** argv) { std::vector<std::shared_ptr<std::string> > v; std::string str = "variable_group x, y, z; "; std::string::const_iterator iter = str.begin(); std::string::const_iterator end = str.end(); systemparser<std::string::const_iterator> s; bool s = phrase_parse(iter, end, s, boost::spirit::ascii::space, v); if (s) { std::cout << "parse succeeded: " << v.size() << " variables\n"; (auto& s : v) std::cout << " - '" << s << "'\n"; } else std::cout << "parse failed\n"; if (iter!=end) std::cout << "remaining unparsed: '" << std::string(iter, end) << "'\n"; return 0; }
the text parsed correctly, resulting vector of length 0, while should of length 3. somehow, std::shared_ptr<string>
not pushed onto of vector resulting rule genericvargp_
.
i've tried many things, including reading debug information test parse, , placement of %=
signs rule definitions, should used rules there semantic action not assign _val
unless mistaken. i've played night , day using phx::bind
manually push onto of _val
, got nowhere. i've further verified make_shared_
provided sehe in answer in fact lazy std::shared_ptr.
as aside, have struggled getting result of unencountered_symbol_
add encountered_variables
enforce uniqueness of variable names...
the problem seems propagation of result of new_variable_
rule onto desired vector of shared pointers in genericvargp_
rule.
this declaration
qi::rule<iterator, std::shared_ptr<std::string()> > new_variable_;
doesn't match desired type:
qi::rule<iterator, std::shared_ptr<std::string>() > new_variable_;
sadly, in old spiritv2 attribute silently ignored , no attribute propagation done. explains why didn't error out on compile time.
#define boost_spirit_use_phoenix_v3 1 #define boost_spirit_debug 1 #include <boost/spirit/include/qi_core.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <iostream> #include <string> #include <boost/spirit/include/phoenix_stl.hpp> #include <boost/phoenix/bind/bind_member_function.hpp> #include <boost/spirit/include/phoenix_fusion.hpp> // solution lazy make shared comes forum, user sehe. // https://stackoverflow.com/questions/21516201/how-to-create-boost-phoenix-make-shared // post found using google search terms `phoenix construct shared_ptr` // changed boost::shared_ptr std::shared_ptr 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> >; } namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; template <typename iterator, typename skipper = ascii::space_type> struct systemparser : qi::grammar<iterator, std::vector<std::shared_ptr<std::string> >(), skipper> { systemparser() : systemparser::base_type(variable_group_) { namespace phx = boost::phoenix; using qi::_1; using qi::_val; using qi::eps; using qi::lit; var_counter = 0; declarative_symbols.add("variable_group", 0); variable_group_ = "variable_group" > genericvargp_ > ';'; genericvargp_ = new_variable_ % ','; // new_variable_ = unencountered_symbol_ [_val = make_shared_<std::string>()(_1)]; unencountered_symbol_ = valid_variable_name_ - (encountered_variables | declarative_symbols); valid_variable_name_ = +qi::alpha >> *(qi::alnum | qi::char_("[]_")); boost_spirit_debug_nodes((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_)) } // rule declarations. these member variables parser. qi::rule<iterator, std::vector<std::shared_ptr<std::string> >(), skipper> variable_group_; qi::rule<iterator, std::vector<std::shared_ptr<std::string> >(), skipper> genericvargp_; qi::rule<iterator, std::shared_ptr<std::string>() > new_variable_; qi::rule<iterator, std::string()> unencountered_symbol_; qi::rule<iterator, std::string()> valid_variable_name_; unsigned var_counter; qi::symbols<char, qi::unused_type> encountered_variables; qi::symbols<char, qi::unused_type> declarative_symbols; }; int main() { std::vector<std::shared_ptr<std::string> > v; std::string str = "variable_group x, y, z; "; std::string::const_iterator iter = str.begin(); std::string::const_iterator end = str.end(); systemparser<std::string::const_iterator> s; bool s = phrase_parse(iter, end, s, boost::spirit::ascii::space, v); if (s) { std::cout << "parse succeeded: " << v.size() << " variables\n"; (auto& s : v) std::cout << " - '" << *s << "'\n"; } else std::cout << "parse failed\n"; if (iter!=end) std::cout << "remaining unparsed: '" << std::string(iter, end) << "'\n"; }
prints
parse succeeded: 3 variables - 'x' - 'y' - 'z'
as lot of debug information
Comments
Post a Comment