2012-12-12 84 views
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’ 

一個解決方案是更改函數解析,以便它通過引用返回參數中的解析值。但我想知道是否還有其他方法。

也許P和Attr是相關的,我在文檔中找不到它(因爲Attr是解析器P返回的類型),因此這可能只是一種類型的模板?

我能代替離開的定義是,並更改呼叫

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

但後來,什麼是X型?

+4

如果有幫助,任何解析器的屬性類型可以通過'typename P :: template attribute :: type'來獲得。但在你的情況下,你可以將'parse'改成'template ',並且只需要指定'Attr',而不是'P':'BOOST_CHECK_EQUAL(解析(qi :: int_,「23」 ),23);'。 – ildjarn

回答

2

您可以使用哈特穆特·凱澤的attribute_of_qi_component元函數從here。這在內部使用了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 
3

從解析器計算兼容屬性類型並不總是可能的,因爲「上下文」通常取決於屬性類型。如果你堅持Spirit的延續式慣例,你將會面臨更少的麻煩。例如,看到測試線束的文檔中: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); }); 
}