【问题标题】:A boost spirit helper function (template with templated return type)增强精神辅助功能(具有模板化返回类型的模板)
【发布时间】:2012-12-12 01:49:02
【问题描述】:

我正在使用 boost spirit,为了简化多个解析器组件的测试,我希望有一个像这样的辅助函数(不起作用)

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 类型是什么?

【问题讨论】:

  • 如果有帮助,任何解析器的属性类型都可以用typename P::template attribute&lt;Context, Iter&gt;::type获取。但在您的情况下,您可以将 parse 更改为 template&lt;typename Attr, typename P&gt; 并且只需要指定 Attr,而不是 P: BOOST_CHECK_EQUAL(parse&lt;int&gt;(qi::int_, "23" ), 23);

标签: c++ templates boost boost-spirit


【解决方案1】:

并不总是可以从解析器计算出兼容的属性类型,因为“上下文”通常取决于属性类型。如果您坚持 Spirit 的延续风格约定,您将面临更少的麻烦。例如,请参阅文档中的测试工具:http://www.boost.org/doc/libs/1_52_0/libs/spirit/doc/html/spirit/qi/reference/basics.html#spirit.qi.reference.basics.examples

你可以像这样集成 boost 测试:

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

【讨论】:

    【解决方案2】:

    您可以使用来自 here 的 Hartmut Kaiser 的 attribute_of_qi_component 元函数。这在内部使用了 il​​djarn 为各个解析器建议的内容,除此之外,还适用于下面的 qi::int_ &gt;&gt; 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-21
      相关资源
      最近更新 更多