Domanda in background: boost.proto + detect invalid terminal before building the expression tree.boost.proto + modifica albero delle espressioni sul posto
Ciao, quello che sto cercando di realizzare è
- creare una copia di un albero di espressione, in cui tutti i vettori sono sostituiti con i loro cominciare iteratori (nel mio caso è un puntatore RAW)
- incrementare gli iteratori sul posto
- iteratori di deviazione nella struttura, ma quella parte dovrebbe essere relativamente semplice.
Così, per 1. Ho finito con questo codice
///////////////////////////////////////////////////////////////////////////////
// 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> > >
>
{};
È possibile che questo riesce a creare un albero in cui tutti i vettori sono sostituiti da puntatori. Fin qui tutto bene. Ora, prova ad incrementare gli iteratori . Mi sono reso conto che sarebbe meglio far avanzare gli iteratori, quindi con una sola trasformazione, potrei ottenere la maggior parte del comportamento dello di un iteratore di accesso casuale (la dereferenziazione è l'altro pezzo mancante). Per 2., il richiesto dovrebbe essere trasformata
///////////////////////////////////////////////////////////////////////////////
// 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> > >
>
{};
Ora, nella funzione principale
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;
}
ottengo il seguente messaggio di errore (filtrato la spazzatura):
array.cpp: 361: 13: errore: assegnazione di sola lettura posizione
'boost::proto::value<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<const double*>, 0l> >((* & var))'
Quello che mi preoccupa è il '((* & var)) "parte ... non riesco a capire cosa fare per risolvere questo problema. Grazie in anticipo, cordiali saluti
PS cosa non collegato: dopo aver giocato un po 'con trasforma, lo schema generale che sto utilizzando è:
- decidere cosa fare per l'albero
- Scrivi una trasformazione primitiva che esegue l'operazione
- Scrivi una grammatica che riconosca dove deve essere applicata la trasformazione, utilizza la trasformazione precedentemente definita
Pensi che sia ragionevole? Voglio dire, è un sacco di codice per eseguire solo un'operazione elementare su un singolo tipo di nodo . Con i contesti, è possibile definire più operazioni contemporaneamente, discriminando il tipo di nodo. E 'possibile farlo anche con le trasformazioni? Qual è lo schema generale da utilizzare?
Il messaggio di errore significa che 'var' (dove si tenta di incrementarlo con' index') è immutabile. Hai provato a utilizzare uno stile più funzionale, in cui la trasformazione restituisce invece l'iteratore successivo? –
@LucDanton Provato, se cambio il tipo di ritorno in iter_advance e restituisco un puntatore modificato (ho verificato che il puntatore è aumentato nella trasformazione), l'albero non viene modificato. Stavo seguendo le "increment_int" sul manuale di proto, ma ora mi rendo conto che è diverso, in quel caso l'albero stava memorizzando i riferimenti a v vars, ora ho i ptrs che sono memorizzati in base al valore nell'albero. Alternative: 1. fare una nuova copia dell'intero albero ogni volta che passo (approccio puramente funzionale?) B) memorizzare i puntatori in un iterator_wrapper come nell'esempio "misto" del manuale. – Giuliano