Hintergrund frage: boost.proto + detect invalid terminal before building the expression tree.boost.proto + modify ausdruck baum in ort
Hallo, was ich versuche zu erreichen, ist
- eine Kopie eines Ausdrucksbaum erstellen, in dem alle Vektoren mit substituiert sind ihre beginnen Iteratoren (in meinem Fall ist ein Rohzeiger)
- inkrementieren die Iteratoren
- deriteration Iteratoren im Baum, aber dieser Teil sollte relativ einfach sein.
So zum 1. endete ich mit diesem Code auf
///////////////////////////////////////////////////////////////////////////////
// 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> > >
>
{};
Die oben gelingt es, einen Baum zu erstellen, in dem alle Vektoren durch Zeiger ersetzt werden. So weit, ist es gut. Versuchen Sie nun, Iteratoren zu inkrementieren. Ich erkannte, dass es besser wäre, Iteratoren weiterzuentwickeln, also konnte ich mit nur einer Transformation das meiste des Verhaltens eines Direktzugriffs-Iterators erhalten (Dereferenz ist das andere fehlende Stück). Für 2. Transformation der erforderlich ist, sollte
///////////////////////////////////////////////////////////////////////////////
// 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> > >
>
{};
nun in der Hauptfunktion
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;
}
Ich erhalte die folgende Fehlermeldung (filtert Junk) sein:
array.cpp: 361: 13: Fehler: Zuweisung von schreibgeschützten Standort
'boost::proto::value<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<const double*>, 0l> >((* & var))'
Was mich stört, ist die ‚((* & var)) 'Teil ... kann nicht verstehen, was zu tun ist, um dies zu beheben. Vielen Dank im Voraus, mit besten Grüßen
PS Unrelated Sache: Nach einem wenig mit Transformationen zu spielen, das allgemeine Muster ich benutze ist:
- Entscheiden Sie, was , um den Baum zu tun
- Schreiben Sie eine primitive Transformation, die die Operation ausführt
- Schreiben Sie eine Grammatik, die erkennt, wo die Transformation angewendet werden soll, verwenden Sie die zuvor definierte Transformation
Glaubst du, das ist vernünftig? Ich meine, es ist eine Menge Code, um nur eine elementare Operation zu einem einzigen Knoten durchzuführen. Mit Kontexten ist es möglich, mehrere Ops auf einmal zu definieren und dabei den Knotentyp zu unterscheiden. Es ist möglich, dies auch mit Transformationen zu tun? Wie ist das allgemeine Muster zu verwenden?
Die Fehlermeldung bedeutet, dass 'var' (wo Sie versuchen, es um 'index' zu erhöhen) unveränderlich ist. Haben Sie versucht, einen funktionaleren Stil zu verwenden, bei dem die Transformation stattdessen den nächsten Iterator zurückgibt? –
@LucDanton Versucht, wenn ich den Rückgabetyp in Iter_Advance ändern und einen geänderten Zeiger zurückgeben (ich habe überprüft, dass der Zeiger in der Transformation erhöht wird), wird der Baum nicht geändert. Ich habe die 'increment_ints' auf dem Manual von proto verfolgt, aber jetzt merke ich, dass es anders ist, in diesem Fall speichert der Baum Verweise auf int vars, jetzt habe ich die ptrs nach Wert im Baum gespeichert. Alternativen: 1. mache jedes Mal eine neue Kopie des gesamten Baums, wenn ich inkrementiere (rein funktionaler Ansatz?) B) speichere die Zeiger in einem iterator_wrapper wie im "gemischten" Beispiel des Handbuchs. – Giuliano