c++boost-phoenixboost-spirit-karma

boost spirit karma generation from a collection of struct using a member function


I am trying to use karma to generate a comma separated list of strings, from a vector of structs that contain a member function that provides the string.

While I can generate single string output using phoenix::bind, and I can generate a csv output from a vector of strings, I am struggling combining the two approaches.

In the following example, the first rule works OK, the second will not compile (using VS2013, boost 1.57), giving a phoenix error: "cannot convert from 'std::vector> *' to 'foo *'", so clearly the semantic action that will work for a single instance of the struct is incorrect in this case. Is the only answer to use a fusion adapter?

#include <iostream>
#include <vector>
#include <string>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace karma = boost::spirit::karma;
namespace phx = boost::phoenix;

struct foo 
{
  std::string f() const { return "bar"; }
};

int main()
{
  std::string output;
  typedef std::back_insert_iterator< std::string > iterator;
  iterator it(output);

  // this works:
  std::vector<std::string> svec = { "foo", "bar", "baz" };
  karma::rule< iterator, std::vector<std::string>() > svec_rule = karma::string % ',';
  karma::generate(it, svec_rule, svec);
  std::cerr << output << '\n';

  // but this won't compile
  std::vector<foo> vfoo(3);
  karma::rule< iterator, std::vector<foo>&() > vfoo_rule = karma::string[karma::_1 = phx::bind(&foo::f, karma::_val)] % ',';
  karma::generate(it, vfoo_rule, vfoo);
  std::cerr << output << '\n';
}

Solution

  • _val represents the vector<foo> in that rule. You can't very well call the foo::f on a vector.

    Instead, make a rule for the foo (or use attr_cast<>):

    karma::rule<iterator, foo()> foo_rule = karma::string [ karma::_1 = phx::bind(&foo::f, karma::_val) ];
    karma::generate(it, foo_rule % ',', vfoo);
    
    std::cerr << output << '\n';
    

    Prints bar,bar,bar