読者です 読者をやめる 読者になる 読者になる

Boost.Spirit.Qi 結果型にタプルを直接使わない

C++

qi::parseの結果を受け取るために、簡単なパースの場合にはFusion Sequenceの型を記述するのがめんどくさいです。

const auto rule = qi::int_ >> ',' >> qi::int_ >> ',' >> qi::int_;

fusion::vector<int, int, int> result; // これ書くのめんどくさい
qi::parse(it, input.end(), rule, result);

qi::parse関数の第4引数以降には、パース結果のそれぞれの要素への参照を可変引数として渡すことができるようです。

const auto rule = qi::int_ >> ',' >> qi::int_ >> ',' >> qi::int_;

int a, b, c;
qi::parse(it, input.end(), rule, a, b, c);

内部的には、参照のfusion::vectorを作って転送しています。

// boost/spirit/home/qi/parse_attr.hpp

template <typename Iterator, typename Expr
  , BOOST_PP_ENUM_PARAMS(N, typename A)>
inline bool
parse(
    Iterator& first
  , Iterator last
  , Expr const& expr
  , BOOST_PP_ENUM_BINARY_PARAMS(N, A, & attr))
{
    ...

    typedef fusion::vector<
        BOOST_PP_ENUM(N, BOOST_SPIRIT_QI_ATTRIBUTE_REFERENCE, A)
    > vector_type;

    vector_type attr (BOOST_PP_ENUM_PARAMS(N, attr));
    return compile<qi::domain>(expr).parse(first, last, unused, unused, attr);
}


サンプル:

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

int main()
{
    const std::string input = "123,456,789";

    int a, b, c;

    const auto rule = qi::int_ >> ',' >> qi::int_ >> ',' >> qi::int_;

    std::string::const_iterator it = input.begin();
    if (!qi::parse(it, input.end(), rule, a, b, c)) {
        std::cout << "parse error" << std::endl;
        return 1;
    }

    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << c << std::endl;
}
123
456
789