Скажем, у нас есть следующий исходный код:
#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
,
Я вижу несколько способов справиться с этим:
std::nullptr_t
от karma::unused_type
в определении грамматики : Это работает на этом примере, но может внести двусмысленность в более сложную грамматику.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;
}
Однако это не имеет никакого смысла, так как документы государство:
lit
, лайкstring
также испускает строку символов. Основное отличие состоит в том, чтоlit
не потребляет [Так в оригинале] атрибут. Простая строка как"hello"
илиstd::basic_string
эквивалентноlit
Так что я просто … по своей прихоти подумал немного навязать вещи, используя тот же обходной путь, который работает для одноэлементные последовательности слияния на стороне ци:
query = karma::eps << "yeah";
И, вуаля: это работает: Жить на Колиру
[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;
};
Я все еще интересуюсь любым комментарием, упреком или другим решением.