4

私は学んboost::spiritでいて、いくつかのテキストを読んで解析して構造体にしようとしています。

たとえば、以下では"2: 4.6"int2およびdoubleとして解析されます。4.6TestStruct

#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;
}

それはうまく機能しますが、このコードをどのように単純化できるのでしょうか?

mystruct0たとえば、タイプをマークするためだけに存在する文法ルールを削除したいと思います。これは、ルールからオブジェクトstd::pair<int,double>を自動的に構築するために使用されます。TestStructmystruct

また、可能であれば、TestStructコンストラクターをから削除できるようにしたいと思います。std::pair

では、次のコードをどういうわけかコンパイルすることができますか?それははるかに良い解決策になるでしょう:

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;
}

残念ながら、コンパイラは次のように述べています。

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

2 に答える 2

3

値を「順次」構造体に解析できるようにするには、ここでfusion説明するように、値をタプルに変換する必要があります。

あなたの場合、これはあなたがする必要があることを意味します

  1. 必要なヘッダーを含める

    #include <boost/fusion/adapted/struct/adapt_struct.hpp>
    
  2. 融合適応構造体マクロを使用します。の宣言の直後にTestStruct配置するのが最適です:

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

これらの2つの変更により、簡略化されたバージョンがコンパイルされ、目的の結果が得られます。現在、それが本当にはるかに単純であるかどうかはわかりませんが、構造体にさらにメンバーを追加する予定がある場合は、将来的に単純化するのに役立つ可能性があるため、これは良い出発点です。

プログラムを単純化するために行うことができる他の大きな変更はありません。

于 2012-05-05T12:09:26.837 に答える
2

はい、そのコードはコンパイルできます。実際、コンストラクターがなくても実行できます。デフォルトの(コンパイラーで生成された)コンストラクターで問題ありません。

あなたがする必要があるのは、融合シーケンスとしてあなたの構造体を適応させることです。(ボーナスとして、これはカルマにも機能します。)これはまさに最初に機能し
た魔法です。std::pair

#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;
}
于 2012-05-05T14:25:51.390 に答える