2

假设我们有以下源代码:

#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无法找到 type 属性的生成器std::nullptr_t

我看到了几种解决方法:

  1. 在语法定义中替换std::nullptr_tkarma::unused_type:它适用于此示例,但可能会在更复杂的语法中引入歧义。
  2. 定义特征专业化:在我看来,这是肮脏的而不是通用的。另外,它暴露了我对每个人的标准类型的专业化,导致潜在的冲突。
  3. 专门化属性转换:专门为我专门化标准类型的问题。
  4. 编写自定义生成器:迄今为止最好的候选者,但与任务复杂性相比,它会产生大量高度模板化的代码行。
  5. 放置一个带有karma::unused_type属性的中间规则。一个有效但没有意义的快速修复。

问题:我如何告诉karma::rule生成一个简单的文字而不关心它的属性是否有生成器?

4

2 回答 2

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

但是,这根本没有意义,因为文档状态:

lit, like string, 也发出一串字符。主要区别在于lit不消耗[原文如此]属性。像"hello"or a这样的普通字符串std::basic_string等价于 alit

所以我只是......一时兴起,想通过使用适用于 Qi 方面的单元素融合序列的相同解决方法来强制执行一些操作:

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

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


[1]

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

于 2014-03-31T19:01:30.207 回答
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;
};

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

于 2014-03-31T15:52:36.047 回答