3

私はブーストスピリットを使用していますが、複数のパーサーコンポーネントのテストを容易にするために、このようなヘルパー関数を使用したいと思います(これは機能しません)。

namespace qi = boost::spirit::qi;
namespace tests {
 template <typename P, typename Attr>
 Attr parse(P const& p, const string& input)
 {
  string::const_iterator f = input.begin();
  string::const_iterator l = input.end();
  Attr parsed;
  qi::phrase_parse(f, l, p, boost::spirit::ascii::space, parsed);
  return parsed;
 }
}

後でこのように呼ぶ

 BOOST_CHECK_EQUAL(parse(qi::int_, "23" ), 23);

コンパイラエラーはこのようなものです

 template<class P, class Attr> Attr tests::parse(const P&, const string&)
 template argument deduction/substitution failed:
 couldn't deduce template parameter ‘Attr’

1つの解決策は、関数parseを変更して、参照によってパラメーター内の解析された値を返すようにすることです。しかし、他の方法があるのだろうか。

おそらくPとAttrは関連していて、ドキュメントでそれを見つけることができないので(AttrはパーサーPが返すタイプであるため)、これは1つのタイプのみのテンプレートである可能性がありますか?

代わりに、定義をそのままにして、呼び出しを次のように変更できますか?

 BOOST_CHECK_EQUAL(parse<X,Y>(qi::int_, "23" ), 23);

では、タイプXは何ですか?

4

2 に答える 2

3

「コンテキスト」は一般に属性タイプに依存するため、パーサーから互換性のある属性タイプを計算できるとは限りません。スピリットの継続スタイルの慣習に固執すれば、問題に直面することは少なくなります。たとえば、ドキュメントのテストハーネスを参照してください:http://www.boost.org/doc/libs/1_52_0/libs/spirit/doc/html/spirit/qi/reference/basics.html#spirit.qi。 reference.basics.examples

次のようにブーストテストを統合できます。

template <typename P, typename F>
void parse(P const& p, const string& input, F f)
{
  qi::phrase_parse(input.begin(), input.end(), p[f], boost::spirit::ascii::space);
}

BOOST_AUTO_TEST_CASE(parse_int)
{
  parse(qi::int_, "23", [] (int x) { BOOST_CHECK_EQUAL( x, 23 ); } );
}
于 2012-12-12T05:36:37.790 に答える
2

ここattribute_of_qi_componentからHartmutKaiserのメタ関数を使用できます。これは、ildjarnが個々のパーサーに対して提案したものを内部的に使用し、それに加えて、以下のような式でも機能します。qi::int_ >> qi::lexeme[ qi::as_string[+qi::char_] ]

#define BOOST_TEST_MODULE attr_of_qi_parsers

#include <boost/test/included/unit_test.hpp>

#include <boost/spirit/include/qi.hpp>
#include <string>
#include <utility>
#include <boost/fusion/include/adapted.hpp>

namespace qi = boost::spirit::qi;


typedef std::pair<int,int> pair_type;
typedef boost::fusion::vector2<int,std::string> vector_int_string;


struct data
{
    data(){}
    data(int m1, int m2): member1(m1), member2(m2) {}

    int member1;
    int member2;
};

std::ostream& operator<<(std::ostream& os, const data& d)
{
    os << "{ 1st: " << d.member1 << ", 2nd: " << d.member2 << " }";
    return os;
}

bool operator==(const data& lhs, const data& rhs)
{
    return lhs.member1 == rhs.member1 && lhs.member2 == rhs.member2;
}

BOOST_FUSION_ADAPT_STRUCT(data,
        (int, member1)
        (int, member2)
)


//BOOST_CHECK_EQUAL requires that the arguments have defined operator<<
//You can either use in the global namespace 
BOOST_TEST_DONT_PRINT_LOG_VALUE(pair_type);

//or define operator<< in the namespace std. This is technically illegal but it works
//namespace std
//{
//  std::ostream& operator<<(std::ostream& os, const std::pair<int,int>& p)
//  {
//      os << "<" << p.first << "," << p.second << ">";
//      return os;
//  }
//}


namespace tests {

    template <typename Expr, typename Iterator = boost::spirit::unused_type>
    struct attribute_of_qi_component
    {
        typedef typename boost::spirit::result_of::compile<
            qi::domain, Expr
        >::type parser_expression_type;

        typedef typename boost::spirit::traits::attribute_of<
            parser_expression_type, 
            boost::spirit::unused_type, Iterator
        >::type type;
    };


    template <typename P>
    typename attribute_of_qi_component<P>::type parse(P const& p, const std::string& input)
    {
        std::string::const_iterator f = input.begin();
        std::string::const_iterator l = input.end();
        typename attribute_of_qi_component<P>::type parsed;
        qi::phrase_parse(f, l, p, boost::spirit::ascii::space, parsed);
        return parsed;
     }



BOOST_AUTO_TEST_CASE(int_parser) {
    BOOST_CHECK_EQUAL(parse(qi::int_, "23" ), 23);
}

BOOST_AUTO_TEST_CASE(int_and_string_parser) {
    BOOST_CHECK_EQUAL(parse(qi::int_ >> qi::lexeme[ qi::as_string[+qi::char_] ], "23 is a number"), vector_int_string(23,"is a number"));
}

BOOST_AUTO_TEST_CASE(pair_rule_parser){
    qi::rule<std::string::const_iterator,pair_type(),boost::spirit::ascii::space_type> pair_rule = qi::int_ >> ',' >> qi::int_;
    BOOST_CHECK_EQUAL(parse(pair_rule,"1, 2"), std::make_pair(1,2));
}

BOOST_AUTO_TEST_CASE(data_rule_parser){
    qi::rule<std::string::const_iterator,data(),boost::spirit::ascii::space_type> data_rule = qi::int_ >> ',' >> qi::int_;
    BOOST_CHECK_EQUAL(parse(data_rule,"2, 4"), data(2,4));
}

}//end of tests namespace
于 2012-12-12T11:56:43.387 に答える