如何在没有提供有效生成器的情况下tel:boost :: karma :: rule不使用它的属性?

时间:2014-03-31 15:22:23

标签: c++ c++11 boost boost-spirit boost-spirit-karma

假设我们有以下源代码:

#include <iostream>
#include <string>
#include <iterator>
#include <boost/spirit/include/karma.hpp>

namespace karma = boost::spirit::karma;

template <typename OutputIterator> struct grammar : karma::grammar<OutputIterator, std::nullptr_t()> {
  grammar() : grammar::base_type(query) {
    query =  "yeah";
  }

  karma::rule<OutputIterator, std::nullptr_t()> query;
};


int main(void) {
  typedef std::back_insert_iterator<std::string> iterator_type;
  std::string generated;
  iterator_type output_it(generated);
  //keys_and_values<sink_type> g;
  grammar<iterator_type> g;
  bool result = karma::generate(output_it, g, nullptr);
  std::cout << result << ":" << generated << std::endl;
  return 0;
}

由于karma缺少std::nullptr_t的某些特征(boost::spirit::traits::extract_c_stringboost::spirit::traits::char traits),因此无法编译。更具体地说,它失败了,因为karma无法为std::nullptr_t类型的属性找到生成器。

我认为有几种方法可以解决这个问题:

  1. 在语法定义中将std::nullptr_t替换为karma::unused_type :它适用于此示例,但可能会在更复杂的语法中引入歧义。
  2. 定义特征专长:在我看来,这是脏的而不是通用的。此外,它为每个人揭示了我对标准类型的专业化,导致潜在的冲突。
  3. Specializing an attribute transform :同样专门针对我的标准类型的问题。
  4. Write a custom generator :目前为止最佳候选人,但与任务复杂性相比,它会严重影响高度模板化的代码行。
  5. 放置具有karma::unused_type属性的中间规则。一个有效的快速修复但没有任何意义。
  6. 问题:如何告诉karma::rule生成一个简单的文字而不关心是否有一个生成器用于其属性?

2 个答案:

答案 0 :(得分:3)

你似乎偶然发现臭名昭着的单元素融合序列的反面难题 [1] :(

我注意到,因为错误来自代码,试图验证输入字符串是否与属性匹配(lit.hpp):

// fail if attribute isn't matched by immediate literal
typedef typename attribute<Context>::type attribute_type;

typedef typename spirit::result_of::extract_from<attribute_type, Attribute>::type
    extracted_string_type;

using spirit::traits::get_c_string;
if (!detail::string_compare(
        get_c_string(
            traits::extract_from<attribute_type>(attr, context))
      , get_c_string(str_), char_encoding(), Tag()))
{
    return false;
}

但是,这完全没有意义,因为 docs 状态:

  与lit一样,

string也会发出一串字符。主要区别在于 lit不会消耗 [sic] 属性。像"hello"std::basic_string这样的普通字符串相当于lit

所以我只是......通过使用适用于Qi方面​​的单元素融合序列的相同解决方法,突然想到要稍微强制一点:

query = karma::eps << "yeah";

而且,瞧瞧:它有效: Live On Coliru


[1] 参见

等。这是一个可能需要为SpiritV2解决的可悲缺陷。

答案 1 :(得分:1)

可能的答案:发布后,我找到了一个满足我的解决方案。那就是:引入一个中间规则。

template <typename OutputIterator> struct grammar : karma::grammar<OutputIterator, std::nullptr_t()> {
  grammar() : grammar::base_type(query) {
    query =  null_rule;
    null_rule = "null";
  }

  karma::rule<OutputIterator, std::nullptr_t()> query;
  karma::rule<OutputIterator, karma::unused_type()> null_rule;
};

我仍然对任何评论,责备或其他解决方案感兴趣。