如何在不提供有效生成器的情况下调用 boost::karma::rule 不消耗其属性

How to tel a boost::karma::rule not to consume its attribute without providing a valid generator?

本文关键字:karma boost 调用 rule 属性 情况下 有效      更新时间:2023-10-16

假设我们有以下源代码:

#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. 专用
  4. 属性转换 :仅为我专用标准类型的相同问题。
  5. 编写自定义生成器 :迄今为止最好的候选者,但与任务复杂性相比,它会产生大量高度模板化的代码行。
  6. 放置具有karma::unused_type属性的中间规则。一个有效的快速修复,但没有意义。

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

你似乎偶然发现了臭名昭著的单元素融合序列难题[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;
}

但是,这根本没有意义,因为文档指出:

litstring一样,也会发出一串字符。主要区别在于lit不消耗属性。像 "hello"std::basic_string 这样的普通字符串等效于lit

所以我只是...心血来潮地想稍微胁迫一下,使用与 Qi 侧单元素融合序列相同的解决方法:

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

而且,瞧:它有效:住在科里鲁


[1] 参见

  • 如何在具有提升精神的 AST 中使用只有一个属性的类?
  • 单成员结构体的灵气属性传播问题
  • 使用BOOST_FUSION_ADAPT_STRUCT调整结构时编译器错误
  • 将包含字符串成员作为合成属性的类调整

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

可能的答案 : 发布此内容后,我找到了暂时令我满意的解决方案。那就是:引入一个中间规则。

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

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