Boost :: Spirit :: Qi. ¿Cómo convertir expresiones de analizador en línea en gramáticas independientes y cómo desempaquetar las tuplas generadas por ellas?

Estoy usando QI y Phoenix, y quiero escribir una pequeña gramática que devuelva 4 bools que se utilizarán como argumentos para una llamada de función dentro de una acción semántica.

Tengo varias funciones que necesitan esas cosas, y hasta ahora he usado este enfoque:

( qi::_bool >>  qi::_bool >>  qi::_bool >>  qi::_bool)
[px::bind(&Bool4Function, spirit::_val, spirit::_1, spirit::_2, spirit::_3, spirit::_4)]

y aunque está bien por sí mismo, usarlo en todo el lugar es simplemente feo y confuso, incluso con 'usar' las partes del espacio de nombres.

Por eso quería extraer esta expresión en una gramática independiente.

Así que probé esto (el crédito va a ildjarn para el banco de pruebas):

///// grammar implementation /////
#include <boost/fusion/include/vector10.hpp>
#include <boost/spirit/include/qi_bool.hpp>
#include <boost/spirit/include/qi_char_.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/qi_operator.hpp>
#include <boost/spirit/include/qi_rule.hpp>
#include <boost/spirit/include/qi_string.hpp>

struct FourBools : boost::spirit::qi::grammar<
    char const*,
    boost::fusion::vector4<bool, bool, bool, bool>()
>
{
    typedef boost::fusion::vector4<bool, bool, bool, bool> attribute_type;

    FourBools() : base_type(start_)
    {
        using boost::spirit::bool_;

        start_
            =   "4bools:"
            >> bool_ >> ','
            >> bool_ >> ','
            >> bool_ >> ','
            >> bool_ >> ';'
            ;
    }

private:
    boost::spirit::qi::rule<
        base_type::iterator_type,
        base_type::sig_type
    > start_;
};
FourBools const fourBools;


///// demonstration of use /////
#include <string>
#include <ios>
#include <iostream>
#include <boost/fusion/include/at_c.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/qi_parse.hpp>



void noDice(bool a, bool b, bool c, bool d) 
{

}

void worksFine(boost::fusion::vector4<bool, bool, bool, bool> a)
{

}
int main()
{
    namespace phx = boost::phoenix;
    namespace spirit = boost::spirit;

    std::string const input("4bools:true,true,true,false;");


    char const* first = input.c_str();
    char const* const last = first + input.size();
    bool const success = spirit::qi::parse(
        first, last,
        fourBools[phx::bind(&noDice, spirit::_1)]
    );


    if (!success)
        std::cout << "parse() failed\n";
    else if (first != last)
        std::cout << "didn't consume all input\n";
    std::cout.flush();
}

Eso no se compila a menos quefourBools[phx::bind(&noDice, spirit::_1)] se reemplaza porfourBools[phx::bind(&worksFine, spirit::_1)].

Eso significa que mi problema es desempaquetar argumentos para que coincidan con la firma de la función que se llamará, ya que el número de argumentos difiere a nivel de firma (una tupla de cuatro bools, frente a cuatro bools por sí mismos).

¿Es posible descomprimir usando marcadores de posición de Phoenix directamente, en lugar de escribir envoltorios que traducen tuplas en argumentos individuales para mis funciones existentes que los necesitan por separado? Si es así, ¿cuál sería la sintaxis para eso? Después de todo, una versión en línea como( qi::_bool >> qi::_bool >> qi::_bool >> qi::_bool) funciona bien cuando está 'desempaquetado' porspirit::_1 - spirit::_4, marcadores de posición.

Esto me da la impresión de que esta versión también devuelve una tupla, y de alguna manera no se puede empaquetar con el enfoque anterior, a diferencia de una gramática que devuelve uno.

¿Cómo trato con esto?

Respuestas a la pregunta(3)

Su respuesta a la pregunta