Pregunta de fondo: boost.proto + detect invalid terminal before building the expression tree.boost.proto + modificar el árbol de expresiones en el lugar
Hola, lo que estoy tratando de lograr es
- crear una copia de un árbol de expresión, donde todos los vectores son sustituidos por sus comenzar iteradores (en mi caso, es el puntero en bruto)
- incremente los iteradores en el lugar
- iteradores de desreferencia en el árbol, pero esa parte debería ser relativamente fácil.
Así, por 1. terminé con este código
///////////////////////////////////////////////////////////////////////////////
// A transform that converts all vectors nodes in a tree to iterator nodes
struct vector_begin : proto::transform <vector_begin>
{
template<typename Expr, typename Unused1, typename Unused2>
struct impl : boost::proto::transform_impl<Expr, Unused1, Unused2>
{
// must strip away the reference qualifier (&)
typedef typename proto::result_of::value<
typename boost::remove_reference<Expr>::type
>::type vector_type;
typedef typename proto::result_of::as_expr
<typename vector_type::const_iterator>::type result_type;
result_type operator()(
typename impl::expr_param var
, typename impl::state_param
, typename impl::data_param) const
{
typename vector_type::const_iterator iter(proto::value(var).begin());
return proto::as_expr(iter); // store iterator by value
}
};
};
struct vector_grammar_begin
: proto::or_ <
proto::when <vector_terminal, vector_begin>
// scalars want to be stored by value (proto stores them by const &), if not the code does not compile...
, proto::when <scalar_terminal, boost::proto::_make_terminal(boost::proto::_byval(boost::proto::_value))>
// descend the tree converting vectors to begin() iterators
, proto::when <proto::nary_expr<_, proto::vararg<vector_grammar_begin> > >
>
{};
Lo anterior tiene éxito para crear un árbol donde todos los vectores se reemplazan por punteros. Hasta aquí todo bien. Ahora, intente incrementar los iteradores . Me di cuenta de que sería mejor avanzar iteradores, por lo que con una sola transformación, podría obtener la mayor parte del comportamiento de un iterador de acceso aleatorio (la otra parte faltante es la desreferencia). 2. Para, el requerido debe ser transformada
///////////////////////////////////////////////////////////////////////////////
// A transform that advances all iterators in a tree
struct iter_advance : proto::transform <iter_advance>
{
template<typename Expr, typename Index, typename Dummy>
struct impl : boost::proto::transform_impl<Expr, Index, Dummy>
{
typedef void result_type;
result_type operator()(
typename impl::expr_param var
, typename impl::state_param index // i'm using state to pass a data :(
, typename impl::data_param) const
{
proto::value(var)+=index; // No good... compile error here :(
}
};
};
// Ok, this is brittle, what if I decide the change vector<D,T>'s iterator type ?
struct iter_terminal
: proto::and_<
proto::terminal<_>
, proto::if_<boost::is_pointer<proto::_value>()>
>
{};
struct vector_grammar_advance
: proto::or_ <
proto::when <iter_terminal, iter_advance>
, proto::terminal<_>
, proto::when <proto::nary_expr<_, proto::vararg<vector_grammar_advance> > >
>
{};
Ahora, en la función principal
template <class Expr>
void check_advance (Expr const &e)
{
proto::display_expr (e);
typedef typename boost::result_of<vector_grammar_begin(Expr)>::type iterator_type;
iterator_type iter = vector_grammar_begin()(e);
proto::display_expr (iter);
vector_grammar_advance()(iter,1);
proto::display_expr (iter);
}
int main (int, char**)
{
vec<3, double> a(1), b(2), c(3);
check_advance(2*a+b/c);
return 0;
}
me sale el siguiente mensaje de error (filtrada a cabo la basura):
array.cpp: 361: 13: error: asignación de sólo lectura ubicación
'boost::proto::value<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<const double*>, 0l> >((* & var))'
lo que me molesta es la '((* & var)) 'parte ... no puede entender qué hacer para arreglar esto. Gracias de antemano, saludos cordiales
PS cosa no relacionada: después de jugar un poco con las transformaciones, el patrón general que estoy usando es:
- Decidir qué hacer con el árbol
- Escriba una transformación primitiva que realiza la operación
- Escriba una gramática que reconozca dónde se debe aplicar la transformación, utilice la transformación definida anteriormente
¿Crees que esto es razonable? Quiero decir, es una gran cantidad de código realizar solo una operación elemental a un solo tipo de nodo . Con contextos, es posible definir varias operaciones a la vez, discriminando en el tipo de nodo. ¿Es posible hacer esto con las transformaciones también? ¿Cuál es el patrón general que se utilizará?
El mensaje de error significa que 'var' (donde intenta incrementarlo por' índice') es inmutable. ¿Has intentado utilizar un estilo más funcional, donde la transformación en cambio devuelve el siguiente iterador? –
@LucDanton Intenté, si cambio el tipo de devolución en iter_advance y devuelvo un puntero modificado (he verificado que el puntero se incrementa en la transformación), el árbol no se cambia. Estaba siguiendo las 'increment_ints' en la gestión de proto, pero ahora me doy cuenta de que es diferente, en ese caso el árbol almacenaba referencias a int vars, ahora tengo los ptrs almacenados por valor en el árbol. Alternativas: 1. hacer una copia nueva de todo el árbol cada vez que incremente (enfoque puramente funcional?) B) almacenar los punteros en un iterator_wrapper como en el ejemplo "mixto" del manual. – Giuliano