需求:给定一个参数,若它为1,则不输出;若为1,则输出且追加乘法运算符。

分析:这个需求是很容易满足的,一个if语句就可以了。即便是用karma,只需要eps + alternative。这里主要研究如何自定义directive来完成这个任务。自定义generator是类似的,可以参照karma中的源码。

实现步骤:

  1. 设计directive的名字,取名为coef_。希望的使用方法coef_[generator]或coef_("*")[generator]。
  2. 使用BOOST_SPIRIT_TERMINAL_NAME_EX宏定义标签
            BOOST_SPIRIT_TERMINAL_NAME_EX(coef_, coef_type);
  3. 然后特化use_directive定义使用方法
            template<>struct use_directive<karma::domain, tag::coef_> : mpl::true_ {};template<typename Arg>struct use_directive < karma::domain, terminal_ex <tag::coef_, fusion::vector1<Arg>>> : traits::is_string<Arg> {};

    其中的fusion::vector1<Arg> 表明()运算符的参数只有一个。

  4. 接下来定义directive的具体规则。规则由一个类实现,然后再将标签(coef_)和实现(coef_directive)关联起来。
    1. 因为要定义的是一个作用在单个generator上的directive(即[]运算符只有一个参数),所以从unary_generator类继承。

                  template <typename Subject>struct coef_directive : unary_generator<coef_directive<Subject> > {};
    2. 接下来需要定义三个嵌套类型,subject_type,properties和attribute。
                      using subject_type = Subject;using properties = typename Subject::properties;template <typename Context, typename Iterator = unused_type>struct attribute : traits::attribute_of<subject_type, Context, Iterator> {};
    3. 然后定义directive的构造函数。很明显,需要两个参数:generator和乘法运算符。
                      coef_directive(Subject subject, std::string string) :subject{ std::move(subject) }, string{ std::move(string) }{}Subject subject;std::string string;
      
    4. 最后是关键的generate函数,它决定了directive如何进行工作。
                      template <typename OutputIterator, typename Context, typename Delimiter, typename Attribute>bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d, Attribute const& attr) const {using attribute_type = typename attribute<Context>::type;if (!traits::has_optional_value(attr)) return false;traits::IsOne<Attribute> IsOne;if (IsOne(traits::extract_from<attribute_type>(attr, ctx))) return true;returnsubject.generate(sink, ctx, d, attr) &&string_generate(sink, string) &&delimit_out(sink, d);}
    5. 然后是一个不太重要的函数what。
                     template <typename Context>info what(Context& context) const {return info("coefficient", subject.what(context));}
  5. 最后需要将coef_和coef_directive关联起来。因为有两种用法,所以需要两次特化。
              template <typename Subject, typename Modifiers>struct make_directive<tag::coef_, Subject, Modifiers> {using result_type = coef_directive<Subject>;result_type operator()(unused_type, Subject const& subject, unused_type) const {return result_type{ subject, "" };}};template <typename Subject, typename Arg, typename Modifiers>struct make_directive<terminal_ex <tag::coef_, fusion::vector1<Arg>>, Subject, Modifiers,typename enable_if<traits::is_string<Arg>>::type> {using result_type = coef_directive<Subject>;template <typename Terminal>result_type operator()(Terminal const& term, Subject const& subject, unused_type) const {return result_type{ subject, fusion::at_c<0>(term.args) };}};
  6. 剩下一点点工作。其中IsOne是这里coef_directive用到的一个traits
               template <typename Subject>struct has_semantic_action<karma::coef_directive<Subject> > : unary_has_semantic_action<Subject> {};template <typename Subject, typename Attribute, typename Context, typename Iterator>struct handles_container<karma::coef_directive<Subject>, Attribute, Context, Iterator>: unary_handles_container<Subject, Attribute, Context, Iterator> {};template<typename T>struct IsOne {bool operator()(T const& t) const {return t == 1;}};

完整代码:

#include <boost/spirit/home/support/terminal.hpp>
#include <boost/spirit/home/support/handles_container.hpp>
#include <boost/spirit/home/support/has_semantic_action.hpp>
#include <boost/spirit/home/karma/delimit_out.hpp>
#include <boost/spirit/home/karma/meta_compiler.hpp>
#include <boost/spirit/home/karma/detail/attributes.hpp>
#include <string>namespace boost {namespace spirit {BOOST_SPIRIT_TERMINAL_NAME_EX(coef_, coef_type);template<>struct use_directive<karma::domain, tag::coef_> : mpl::true_ {};template<typename Arg>struct use_directive < karma::domain, terminal_ex <tag::coef_, fusion::vector1<Arg>>> : traits::is_string<Arg> {};namespace karma {using spirit::coef_;using spirit::coef_type;template <typename Subject>struct coef_directive : unary_generator<coef_directive<Subject> > {using subject_type = Subject;using properties = typename Subject::properties;template <typename Context, typename Iterator = unused_type>struct attribute : traits::attribute_of<subject_type, Context, Iterator> {};coef_directive(Subject subject, std::string string) :subject{ std::move(subject) }, string{ std::move(string) }{}template <typename OutputIterator, typename Context, typename Delimiter, typename Attribute>bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d, Attribute const& attr) const {using attribute_type = typename attribute<Context>::type;if (!traits::has_optional_value(attr)) return false;traits::IsOne<Attribute> IsOne;if (IsOne(traits::extract_from<attribute_type>(attr, ctx))) return true;returnsubject.generate(sink, ctx, d, attr) &&string_generate(sink, string) &&delimit_out(sink, d);}template <typename Context>info what(Context& context) const {return info("coefficient", subject.what(context));}Subject subject;std::string string;};template <typename Subject, typename Modifiers>struct make_directive<tag::coef_, Subject, Modifiers> {using result_type = coef_directive<Subject>;result_type operator()(unused_type, Subject const& subject, unused_type) const {return result_type{ subject, "" };}};template <typename Subject, typename Arg, typename Modifiers>struct make_directive<terminal_ex <tag::coef_, fusion::vector1<Arg>>, Subject, Modifiers,typename enable_if<traits::is_string<Arg>>::type> {using result_type = coef_directive<Subject>;template <typename Terminal>result_type operator()(Terminal const& term, Subject const& subject, unused_type) const {return result_type{ subject, fusion::at_c<0>(term.args) };}};}namespace traits {template <typename Subject>struct has_semantic_action<karma::coef_directive<Subject> > : unary_has_semantic_action<Subject> {};template <typename Subject, typename Attribute, typename Context, typename Iterator>struct handles_container<karma::coef_directive<Subject>, Attribute, Context, Iterator>: unary_handles_container<Subject, Attribute, Context, Iterator> {};template<typename T>struct IsOne {bool operator()(T const& t) const {return t == 1;}};}}
}

测试代码:

#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <iostream>
int main() {std::vector<std::pair<int, int>> v{ {1,1},{2,2},{3,3} };namespace karma = boost::spirit::karma;std::cout << karma::format((karma::coef_("*")[karma::auto_] << karma::auto_) % " + ", v) << "\n";return 0;
}

运行结果:


Boost.Spirit.Karma 自定义directive相关推荐

  1. boost::spirit::karma::real_generator相关的测试程序

    boost::spirit::karma::real_generator相关的测试程序 实现功能 C++实现代码 实现功能 boost::spirit::karma::real_generator相关 ...

  2. boost::spirit::karma::detail::format_manip相关的测试程序

    boost::spirit::karma::detail::format_manip相关的测试程序 实现功能 C++实现代码 实现功能 boost::spirit::karma::detail::fo ...

  3. 【BOOST C++字串专题11】Boost.Spirit(一)

    目录 一.Boost.Spirit库介绍 二. boost::spirit::qi::parse()解析格式 三.解析器 一.Boost.Spirit库介绍 本章介绍库 Boost.Spirit. B ...

  4. boost spirit ——编译器,语法解析器

    Spirit 是什么 简单来说,Spirit 是一个 parser generator,功能与 Yacc,ANTLR 类似,且也是基于 EBNF 来描述文法,再基于文法生成 parser,但与前面这些 ...

  5. boost::spirit模块实现自定义karma计数器的测试程序

    boost::spirit模块实现自定义karma计数器的测试程序 实现功能 C++实现代码 实现功能 boost::spirit模块实现自定义karma计数器的测试程序 C++实现代码 #inclu ...

  6. boost::spirit模块实现自定义用作容器数据的测试程序

    boost::spirit模块实现自定义用作容器数据的测试程序 实现功能 C++实现代码 实现功能 boost::spirit模块实现自定义用作容器数据的测试程序 C++实现代码 #include & ...

  7. boost::spirit模块实现自定义嵌入式容器数据的测试程序

    boost::spirit模块实现自定义嵌入式容器数据的测试程序 实现功能 C++实现代码 实现功能 boost::spirit模块实现自定义嵌入式容器数据的测试程序 C++实现代码 #include ...

  8. boost::spirit模块实现演示自定义的、用户定义的类型如何作为标记值类型轻松地与词法分析器集成

    boost::spirit模块实现演示自定义的.用户定义的类型如何作为标记值类型轻松地与词法分析器集成 实现功能 C++实现代码 实现功能 boost::spirit模块实现演示自定义的.用户定义的类 ...

  9. boost::spirit模块实现利用 Karma 生成器的替代方案和内置匹配功能的测试程序

    boost::spirit模块实现利用 Karma 生成器的替代方案和内置匹配功能的测试程序 实现功能 C++实现代码 实现功能 boost::spirit模块实现利用 Karma 生成器的替代方案和 ...

最新文章

  1. ORB_SLAM2局部建图线程
  2. 自然语言处理数据集免费资源开放(附学习资料)
  3. 医学影像AI:全球市场展望
  4. 动易SiteFactory CMS自动采集器 V2.0
  5. MYSQL电脑客户端免安装教程以及出现问题解决方案
  6. hbase1.1.1 连接集群_Hadoop2.7.1+Hbase1.1.2集群环境搭建(10) hadoop hbase kerberos
  7. ASP.net 省市级联(用户控件)适用用framework3.5以上版本
  8. redis的简单安装和配置文件的参数
  9. springboot学习笔记-3 整合redismongodb
  10. 软考计算机网络初级试题答案,2015年下半年中级软考《计算机网络—网络工程师》试题及答案...
  11. Gerber文件总结
  12. 双绞线的线序568A与568B
  13. linux虚拟机界面菜单栏和任务栏不见了,已解决
  14. 剧院在线选座票务系统
  15. PHP微信怎么计步数,微信运动怎么关注好友步数(微信运动计步功能使用方法介绍)...
  16. debug命令(debug命令的使用)
  17. 人工智能:智慧环保(上海AI智慧环保,绿色新时代)
  18. signed integer overflow: -2147483648 - 1 cannot be represented in type ‘int‘
  19. Spring cloud报错com.netflix.hystrix.exception.HystrixRuntimeException
  20. 【多线程】多线程基础知识

热门文章

  1. 射影几何----著名的帕斯卡定理的证明
  2. Supporting Online Material for Lab Experiments for the Study of Social-Ecological Systems
  3. SQL注入--报错和盲注
  4. [附源码]Python计算机毕业设计服装销售商城系统
  5. 计算机OSI七层参考模型
  6. 【Neuralink 与大脑的神奇未来】Part 4:Neuralink 的挑战
  7. HTML5 CSS控制Table内外边框、颜色、大小示例
  8. 是面试官放水,还是公司实在是太缺人?这都没挂,字节原来这么容易进...
  9. 机器学习实战 支持向量机SVM 代码解析
  10. WTD测试框架(一)框架功能模块