Как сказать 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 не потребляет [Так в оригинале] атрибут. Простая строка как "hello" или std::basic_string эквивалентно lit

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

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

И, вуаля: это работает: Жить на Колиру


[1] Увидеть

И т. Д. Это печальный недостаток, который, возможно, нужно будет обойти для SpiritV2.

3

Другие решения

вариант ответа После публикации я нашел решение, которое на данный момент меня устраивает. То есть: ввести промежуточное правило.

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

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

1