Inconsistent Generator directive column behavior i

2019-02-26 01:23发布

问题:

I am writing a karma generator to generate a HTML page and I am experiencing inconsistent behavior while using column directive. It could very well be my understanding of how it works.

Basically I am generating a grid which requires me to insert some delimiters after every 2 occurrences of the data.

The below is a basic program I adopted to do a test run.

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/struct.hpp>
#include <boost/fusion/include/nview.hpp>
#include <boost/assign/std/vector.hpp>

namespace fusion = boost::fusion;
namespace karma = boost::spirit::karma;

///////////////////////////////////////////////////////////////////////////////
namespace client
{
    //  Our employee struct
    struct employee
    {
        int num;
        std::string datatype;
        std::string dataname;
        std::string inputicon;
    };

    // define iterator type
    typedef std::back_insert_iterator<std::string> iterator_type;

}

BOOST_FUSION_ADAPT_STRUCT(
        client::employee,
        (int, num)
                (std::string, datatype)
                (std::string, dataname)
                (std::string, inputicon)
)

///////////////////////////////////////////////////////////////////////////////
int main()
{
    std::string str;

    // some employees
    client::employee john = { 25, "int", "sra_command","fa fa-wrench" };
    client::employee mary = { 25, "float", "swt_command","fa fa-wrench" };
    client::employee tom = { 25, "double", "msc_command","fa fa-mobile" };

    // now make a list of all employees and print them all
    std::vector<client::employee> employees;
    {
        using namespace boost::assign;
        employees += john, mary, tom;
    }

    {
        typedef
        fusion::result_of::as_nview<client::employee const, 1, 2, 3>::type
                names_and_salary;


        karma::rule<client::iterator_type, names_and_salary()> small_box  =
                                                   "<startofblock>"  <<  karma::string << "<after_first>"
                                                                    << karma::string << "<after_second>"
                                                                    << karma::string << "<after_third>";

        std::string generated;
        typedef std::back_insert_iterator<std::string> sink_type;
        sink_type sink(generated);
        karma::generate_delimited(sink, karma::columns(2,karma::string("nth_delimiter"))[small_box % karma::eol],karma::space,employees );

        std::cout << generated << std::endl;
    }
    return 0;
}

The above generates the following output :

<startofblock>int<after_first>sra_command<after_second>fa fa-wrench<after_third> 
 nth_delimiter<startofblock>float<after_first>swt_command<after_second>fa fa-wrench<after_third> 
 nth_delimiter<startofblock>double<after_first>msc_command<after_second>fa fa-mobile<after_third> nth_delimiter

As noted , the nth delimiter occurs after every generation instead of every second.

The expected output is

<startofblock>int<after_first>sra_command<after_second>fa fa-wrench<after_third> 
<startofblock>float<after_first>swt_command<after_second>fa fa-wrench<after_third>  
 nth_delimiter<startofblock>double<after_first>msc_command<after_second>fa fa-mobile<after_third> 

回答1:

I think this comes close to what you want to achieve. Like I said, the last (incomplete) run will still be "terminated" with an nth_delimiter tag:

Live On Coliru

#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/struct.hpp>
#include <boost/fusion/include/nview.hpp>

///////////////////////////////////////////////////////////////////////////////
namespace client {
    struct employee
    {
        int num;
        std::string datatype;
        std::string dataname;
        std::string inputicon;
    };

    typedef std::back_insert_iterator<std::string> iterator_type;
}

BOOST_FUSION_ADAPT_STRUCT(client::employee, /*num,*/ datatype, dataname, inputicon)

///////////////////////////////////////////////////////////////////////////////
int main() {
    // some employees
    std::vector<client::employee> const employees {
        { 25, "int",    "sra_command","fa fa-wrench" },
        { 26, "float",  "swt_command","fa fa-wrench" },
        { 27, "double", "msc_command","fa fa-mobile" },
        { 28, "int",    "sra_command","fa fa-wrench" },
        { 29, "float",  "swt_command","fa fa-wrench" },
        { 30, "double", "msc_command","fa fa-mobile" },
        { 31, "int",    "sra_command","fa fa-wrench" },
        { 32, "float",  "swt_command","fa fa-wrench" },
        { 33, "double", "msc_command","fa fa-mobile" },
    };

    // now print them all
    std::string generated;
    {
        using namespace boost::spirit::karma;

        using Sink = client::iterator_type;
        //using Attr = boost::fusion::result_of::as_nview<client::employee const, 1, 2, 3>::type;
        using Attr = client::employee;
        rule<Sink, Attr()> small_box  = "<B>" << string << "<1>" << string << "<2>" << string << "<3>";

        generate(Sink(generated), columns(2, "<nth_delimiter>\n") [+small_box], employees);
    }

    std::cout << generated << std::endl;
}

Prints

<B>int<1>sra_command<2>fa fa-wrench<3><B>float<1>swt_command<2>fa fa-wrench<3><nth_delimiter>
<B>double<1>msc_command<2>fa fa-mobile<3><B>int<1>sra_command<2>fa fa-wrench<3><nth_delimiter>
<B>float<1>swt_command<2>fa fa-wrench<3><B>double<1>msc_command<2>fa fa-mobile<3><nth_delimiter>
<B>int<1>sra_command<2>fa fa-wrench<3><B>float<1>swt_command<2>fa fa-wrench<3><nth_delimiter>
<B>double<1>msc_command<2>fa fa-mobile<3><nth_delimiter>

Bonus:

The problem with smallbox % eol is that smallbox is an element, and eol too:

    generate(Sink(generated), columns(4, "<nth_delimiter>") [small_box % eol], employees);

Live On Coliru

<B>int<1>sra_command<2>fa fa-wrench<3>
<B>float<1>swt_command<2>fa fa-wrench<3>
<nth_delimiter><B>double<1>msc_command<2>fa fa-mobile<3>
<B>int<1>sra_command<2>fa fa-wrench<3>
<nth_delimiter><B>float<1>swt_command<2>fa fa-wrench<3>
<B>double<1>msc_command<2>fa fa-mobile<3>
<nth_delimiter><B>int<1>sra_command<2>fa fa-wrench<3>
<B>float<1>swt_command<2>fa fa-wrench<3>
<nth_delimiter><B>double<1>msc_command<2>fa fa-mobile<3><nth_delimiter>