boostboost-spiritboost-variantboost-spirit-karma

boost::spirit::karma output of string in quotation marks


I am trying to escape a string in quotation marks using boost::spirit::karma. This works fine if it's just a string. However, for a string in a boost::variant in a std::vector, it does not. Just printing the string does work however, I do not quite understand why.

Line (1) works fine, but doesn't do what I want. Line (2) should do it, but doesn't.

#include <iostream>
#include <string>
#include <boost/variant.hpp>
#include <boost/spirit/include/karma.hpp>
namespace karma = boost::spirit::karma;

typedef std::vector<boost::variant<int, std::string>> ParameterList;
typedef boost::variant<int, std::string, ParameterList> Parameter;

main()
{
    using karma::int_;
    using boost::spirit::ascii::string;
    using karma::eol;
    using karma::lit;

    std::string generated;
    std::back_insert_iterator<std::string> sink(generated);

    // (1)
    karma::rule<std::back_insert_iterator<std::string>, ParameterList()> parameterListRule = (int_ | string) % lit(", "); // This works!

    // (2)
    //karma::rule<std::back_insert_iterator<std::string>, ParameterList()> parameterListRule = (int_ | (lit('"') << string << lit('"'))) % lit(", "); // This does not work

    karma::rule<std::back_insert_iterator<std::string>, Parameter()> parameterRule = (int_ | (lit('"') << string << lit('"')) | parameterListRule) << eol; // This does work, even though it also escapes the string in a pair of quotation marks

    karma::generate(sink, parameterRule, 1); // Works
    karma::generate(sink, parameterRule, "foo"); // Works
    karma::generate(sink, parameterRule, Parameter(ParameterList{1, "foo"})); // Only works using rule (1), not with (2)
    std::cout << generated;
}

Solution

  • If you iterate your data types, you should iterate your rules.

    #include <iostream>
    #include <string>
    #include <boost/variant.hpp>
    #include <boost/spirit/include/karma.hpp>
    namespace karma = boost::spirit::karma;
    
    typedef boost::variant<int, std::string> Item;
    typedef std::vector<Item> ParameterList;
    typedef boost::variant<int, std::string, ParameterList> Parameter;
    
    int main()
    {
      using karma::int_;
      using boost::spirit::ascii::string;
      using karma::eol;
      using karma::lit;
    
      std::string generated;
      std::back_insert_iterator<std::string> sink(generated);
    
      karma::rule<std::back_insert_iterator<std::string>, Item()> itemRule =
          int_ | (lit('"') << string << lit('"'));
    
      karma::rule<std::back_insert_iterator<std::string>, ParameterList()>
        parameterListRule =  itemRule % lit(", ");
    
      karma::rule<std::back_insert_iterator<std::string>, Parameter()>
        parameterRule = (int_ | (lit('"') << string << lit('"')) | parameterListRule) << eol;
    
      karma::generate(sink, parameterRule, 1);
      karma::generate(sink, parameterRule, "foo");
      karma::generate(sink, parameterRule, Parameter(ParameterList {1, "foo"}));
      std::cout << generated;
    
      return 0;
    }