Say we have the following source code:
#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;
}
This fails to compile because karma
lacks some traits for std::nullptr_t
(those are boost::spirit::traits::extract_c_string
and boost::spirit::traits::char traits
). More specifically, it fails because karma
is not able to find a generator for an attribute of type std::nullptr_t
.
I see several ways to cope with that:
std::nullptr_t
by karma::unused_type
in the grammar definition : It works on this example but may introduce ambiguity in a more complex grammar.karma::unused_type
attribute. A quick fix that works but have no sense.Question : How can I tell the karma::rule
to generate a simple literal and not care about having or not a generator for its attribute ?
You seem to have stumbled on the inverse of the infamous single-element fusion sequence conundrum[1] :(
I noticed, because the error emanates from the code trying to verify that the input string matches the attribute (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;
}
However, that makes no sense at all, since the docs state:
lit
, likestring
, also emits a string of characters. The main difference is thatlit
does not consumes [sic] an attribute. A plain string like"hello"
or astd::basic_string
is equivalent to alit
So I just... on a whim thought to coerce things a little, by using the same workaround that works for single-element fusion sequences on the Qi side:
query = karma::eps << "yeah";
And, voilà: it works: Live On Coliru
[1] See
Etc. This is a sad flaw that will probably need to be worked around for SpiritV2.