How to analyze text in a structure using boost :: spirit?

I am learning boost::spirit , and I am trying to read and parse some text in a structure.

For example, "2: 4.6" parsed as int 2 and double 4.6 in my TestStruct below:

 #include <iostream> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/support_istream_iterator.hpp> #include <boost/fusion/include/std_pair.hpp> namespace qi = boost::spirit::qi; struct TestStruct { int myint; double mydouble; TestStruct() {} TestStruct(std::pair<int,double> p) : myint(p.first), mydouble(p.second) {} }; template <typename Iterator, typename Skipper> struct MyGrammar : qi::grammar<Iterator, TestStruct(), Skipper> { MyGrammar() : MyGrammar::base_type(mystruct) { mystruct0 = qi::int_ >> ":" >> qi::double_; mystruct = mystruct0; } qi::rule<Iterator, std::pair<int,double>(), Skipper> mystruct0; qi::rule<Iterator, TestStruct(), Skipper> mystruct; }; int main() { typedef boost::spirit::istream_iterator It; std::cin.unsetf(std::ios::skipws); It it(std::cin), end; // input example: "2: 3.4" MyGrammar<It, qi::space_type> gr; TestStruct ts; if (qi::phrase_parse(it, end, gr, qi::space, ts) && it == end) std::cout << ts.myint << ", " << ts.mydouble << std::endl; return 0; } 

This works well, but I wonder how this code can be simplified?

For example, I would like to get rid of the mystruct0 grammar mystruct0 , which exists only there, to mark the type std::pair<int,double> , which is then used to automatically assemble the TestStruct object from the mystruct rule.

I would also like, if possible, to get rid of the TestStruct constructor from std::pair .

So, is it possible to somehow compile the following code? That would be much nicer:

 struct TestStruct { int myint; double mydouble; TestStruct() {} TestStruct(int i, double d) : myint(i), mydouble(d) {} }; template <typename Iterator, typename Skipper> struct MyGrammar : qi::grammar<Iterator, TestStruct(), Skipper> { MyGrammar() : MyGrammar::base_type(mystruct) { mystruct = qi::int_ >> ":" >> qi::double_; } qi::rule<Iterator, TestStruct(), Skipper> mystruct; }; int main() { typedef boost::spirit::istream_iterator It; std::cin.unsetf(std::ios::skipws); It it(std::cin), end; // input example: "2: 3.4" MyGrammar<It, qi::space_type> gr; TestStruct ts; if (qi::phrase_parse(it, end, gr, qi::space, ts) && it == end) std::cout << ts.myint << ", " << ts.mydouble << std::endl; return 0; } 

Unfortunately, the compiler says:

 boost_1_49_0/include/boost/spirit/home/qi/detail/assign_to.hpp:123: error: no matching function for call to 'TestStruct::TestStruct(const int&)' 
+4
source share
2 answers

Yes, this code can be compiled. In fact, you can do without constructors: the default constructor (generated by the compiler) is fine.

All you have to do is adapt your structure as a merge sequence. (As a bonus, this also works for karma.)
This is exactly the magic that did std::pair in the first place.

 #include <iostream> #include <boost/spirit/include/qi.hpp> #include <boost/fusion/adapted/struct.hpp> namespace qi = boost::spirit::qi; struct TestStruct { int myint; double mydouble; }; BOOST_FUSION_ADAPT_STRUCT(TestStruct, (int, myint)(double, mydouble)); template <typename Iterator, typename Skipper> struct MyGrammar : qi::grammar<Iterator, TestStruct(), Skipper> { MyGrammar() : MyGrammar::base_type(mystruct) { mystruct = qi::int_ >> ":" >> qi::double_; } qi::rule<Iterator, TestStruct(), Skipper> mystruct; }; int main() { typedef std::string::const_iterator It; const std::string input("2: 3.4"); It it(input.begin()), end(input.end()); MyGrammar<It, qi::space_type> gr; TestStruct ts; if (qi::phrase_parse(it, end, gr, qi::space, ts) && it == end) std::cout << ts.myint << ", " << ts.mydouble << std::endl; return 0; } 
+2
source

To be able to analyze values โ€‹โ€‹โ€œsequentiallyโ€ in the structure, you need to convert it to a fusion tuple, as described here .

In your case, that means you need

  • Include required title

     #include <boost/fusion/adapted/struct/adapt_struct.hpp> 
  • Use the macro merge-adaptation structure. Best immediately after the TestStruct :

     BOOST_FUSION_ADAPT_STRUCT( TestStruct, (int,myint) (double,mydouble) ) 

With these two changes, your simplified version compiles and produces the desired results. Not sure if this is much easier now? but if you plan to add other members to your structure, this is a good starting point, as this may simplify your work in the future.

I do not see any other significant changes that you could make to make the program simpler.

+3
source

Source: https://habr.com/ru/post/1410791/


All Articles