spirit::qiとboost::variantの併用について調べた


その後、調べた限りでは、spirit::qiは、boost::variantと併用されることが結構ある。

なぜか。
1つには、複数の型(int, double, bool..)を持つ入力を処理することがあるためである。

コードを見てみる。。。

 1#include <boost/spirit/include/qi.hpp>
 2#include <boost/variant.hpp>
 3#include <string>
 4#include <vector>
 5#include <iostream>
 6
 7using namespace boost::spirit;
 8
 9template <typename Iterator, typename Skipper>
10struct QI_grammar : qi::grammar<Iterator,
11  std::vector<boost::variant<int, bool>>(), Skipper>
12{
13  QI_grammar() : QI_grammar::base_type{values}
14  {
15    value = qi::int_ | qi::bool_;
16    values = value % ',';
17  }
18
19  qi::rule<Iterator, boost::variant<int, bool>(), Skipper> value;
20  qi::rule<Iterator, std::vector<boost::variant<int, bool>>(), Skipper>
21    values;
22};
23
24struct display : public boost::static_visitor<>
25{  
26  template <typename T>
27  void operator()(T t) const
28  {
29    std::cout << std::boolalpha << t << ';';
30  }
31};
32
33int main()
34{
35  std::string s;
36  std::getline(std::cin, s);
37  auto it = s.begin();
38  QI_grammar<std::string::iterator, ascii::space_type> g;
39  std::vector<boost::variant<int, bool>> v;
40  if (qi::phrase_parse(it, s.end(), g, ascii::space, v))
41  {
42    for (const auto &elem : v)
43      boost::apply_visitor(display{}, elem);
44  }
45}

ここで、13-21行目に注目する。

+c++
13 QI_grammar() : QI_grammar::base_type{values}
14 {
15 value = qi::int_ | qi::bool_;
16 values = value % ',';
17 }
18
19 qi::rule<Iterator, boost::variant<int, bool>(), Skipper> value;
20 qi::rule<Iterator, std::vector<boost::variant<int, bool>>(), Skipper>
21 values;
+

15行目で、intかbool型をパースするルールを定義し、19行目でそれを受けている。
19行目で、boost::variantを使っている。

+c++
15 value = qi::int_ | qi::bool_;
19 qi::rule<Iterator, boost::variant<int, bool>(), Skipper> value;
+

boost::variantにはいろいろな説明があるが、捉え方としては「複数の型を持つタプル」というアイディアがある。

実行してみる。。。


$ ./a.out 
false
false;
$ ./a.out
string
$ ./a.out
1,true,2,false,3,wrongString,4,true
1;
true;
2;
false;
3;

intとbool型だけ受け付けているのがわかる。(`ー´)b