Как сказать boost::karma::rule, чтобы не использовать его атрибут без предоставления корректного генератора?

Скажем, у нас есть следующий исходный код:

#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_string а также boost::spirit::traits::char traits). Точнее говоря, это не удается, потому что karma не может найти генератор для атрибута типа std::nullptr_t,

Я вижу несколько способов справиться с этим:

  1. замещать std::nullptr_t от karma::unused_type в определении грамматики: он работает на этом примере, но может внести двусмысленность в более сложную грамматику.
  2. Определение специализации черт: На мой взгляд, это грязно и не является общим. Кроме того, это раскрывает мою специализацию стандартного типа для всех, что ведет к потенциальным конфликтам.
  3. Специализация преобразования атрибута: та же проблема специализации стандартного типа только для меня.
  4. Написать собственный генератор: лучший кандидат на данный момент, но он серьезно загружает высокотемпературные строки кода по сравнению со сложностью задачи.
  5. Поместите промежуточное правило с karma::unused_type атрибут Быстрое исправление, которое работает, но не имеет смысла.

Вопрос: Как я могу сказать karma::rule генерировать простой литерал и не заботиться о наличии или отсутствии генератора для его атрибута?

2 ответа

Решение

Вы, кажется, наткнулись на обратную сторону печально известной головоломки одноэлементной последовательности слияния [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, лайк stringтакже испускает строку символов. Основное отличие состоит в том, что litне потребляет [sic] атрибут. Простая строка как "hello" или std::basic_string эквивалентно lit

Так что я просто... по своей прихоти думал немного привести в порядок, используя тот же обходной путь, который работает для одноэлементных последовательностей слияния на стороне Ци:

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

И, вуаля: это работает: Live On Coliru


[1] См.

И т. Д. Это печальный недостаток, который, вероятно, нужно будет обойти для 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;
};

Я все еще интересуюсь любым комментарием, упреком или другим решением.

Другие вопросы по тегам