dato che boost::tuple non prevede cicli, penso che il modo più
semplice sarebbe scomodare boost::fusion
il problema è che fusion è nella 1.35 di boost e noi, per altri
motivi, siamo al momento fermi alla 1.34.1
qualche altra idea?
thanks in advance
ciao,
Marco
Non conosco benissimo boost::tuple, ma con poche righe di codice (che metto
in fondo al messaggio) ho creato una funzione template 'for_each', che ti
permette di invocare un oggetto funzione su ogni elemento della tupla.
struct print
{
template< class T >
void operator()( const T& v )
{ cout << v << endl;
}
};
int main()
{
tuple<int,char,std::string> t;
t.get<0>() = 1;
t.get<1>() = 'C';
t.get<2>() = "foo";
for_each( t, print() );
}
Ovviamente si possono fare cose pi� sofisticate, e pi� eleganti, come quelle
che fa fusion. Ma se ti basta questo, il codice � sotto la firma.
Max
#include "boost/tuple/tuple.hpp"
template< int Num, class Tuple, class Pred >
struct
for_each_impl
{
for_each_impl( const Tuple& t, Pred op )
{ using namespace boost;
// non ho capito perch�, ma senza questo using non compila
for_each_impl<Num-1,Tuple,Pred> prev(t,op);
op( t.get<Num>() );
}
};
template< class Tuple, class Pred >
struct
for_each_impl<0,Tuple,Pred>
{
for_each_impl( const Tuple& t, Pred op )
{ using namespace boost;
op( t.get<0>() );
}
};
template< class Tuple, class Pred >
void
for_each( const Tuple& t, Pred op )
{
for_each_impl< tuples::length<Tuple>::value-1,Tuple,Pred> impl(t,op);
};
>
> dato che boost::tuple non prevede cicli, penso che il modo pi�
> semplice sarebbe scomodare boost::fusion
>
> il problema � che fusion � nella 1.35 di boost e noi, per altri
> Non conosco benissimo boost::tuple, ma con poche righe di codice (che metto
> in fondo al messaggio) ho creato una funzione template 'for_each', che ti
> permette di invocare un oggetto funzione su ogni elemento della tupla.
pensavo a qualcosa di già pronto (magari in qualche parte di boost che
non conoscevo)
Max, me lo hai addirittura implementato :-)
grazie,
Marco
P.S. per la cronaca sul VC2500 non serve
using namespace boost;
Visto che anche uno dei GCC più recenti (4.1.3) non compila quel codice
senza aggiungere lo 'using', mi piacerebbe capire quale dovrebbe essere il
comportamento del compilatore a norma di standard.
Se riscrivo la parte incriminata come
op( t.template get<0>() ); /* aggiungendo 'template' */
anche il GCC lo compila senza 'using'.
Mi pare che in questi casi la keyword "template" sia in effetti
obbligatoria, essendo 'get' un "dependent name".
Il fatto che GCC lo compili con lo 'using' semprerebbe, perciò, accidentale.
Max
ho dato un occhiata agli header di tuple: get è un metodo di un
ancestor di tuple
di conseguenza non dovrebbe neanche servire scomodare il Koenig lookup
per rintracciarlo:
è semplicmente un metodo ereditato dalla classe
sinceramente non capisco perchè sia necessaria la keyword
"template" (o in alternativa lo "using")
Marco
Sì, però, poiché la mia classe è templatizzata proprio sul tipo a cui viene
applicato 'get', quel nome è un "dependent name". Questo dettaglio è
essenziale.
> sinceramente non capisco perchè sia necessaria la keyword
> "template" (o in alternativa lo "using")
La keyword 'template' è necessaria perché lo Standard richiede che il
compilatore abbia informazioni sufficienti per disanbiguare sintatticamente
l'espressione in questione prima dell'effettiva instanziazione. Sapere che
un "dependent name" si riferisce a un template, consente di decidere come
interpretare il segni '<' e '>', che altrimenti genererebbero ambiguità.
Basta considerare questo codice
t.get<0>(arg) ;
e immaginare di instanziarlo per un tipo che abbia un membro 'get', a cui
sia possibile applicare l'operatore '<'.
Gli estensori dello Standard hanno deciso che certe ambiguità devono essere
risolte nella primissima fase di compilazione di un template.
Alcuni compilatori, evidentemente, posticipano tutte le decisioni al momento
in cui il template viene istanziato. Questo non è conforme allo Standard, e
può portare a istanziazioni che non dovrebbero essere consentite.
Non so perché, invece, GCC compili quel codice se si aggiunge lo 'using'.
Non trovo ragioni valide, e -come ho detto- tendo a credere che sia un
fatto accidentale.
Max
> La keyword 'template' è necessaria perché lo Standard richiede che il
> compilatore abbia informazioni sufficienti per disanbiguare sintatticamente
> l'espressione in questione prima dell'effettiva instanziazione. Sapere che
> un "dependent name" si riferisce a un template, consente di decidere come
> interpretare il segni '<' e '>', che altrimenti genererebbero ambiguità.
> Basta considerare questo codice
>
> t.get<0>(arg) ;
>
> e immaginare di instanziarlo per un tipo che abbia un membro 'get', a cui
> sia possibile applicare l'operatore '<'.
si, adesso è chiaro
> Gli estensori dello Standard hanno deciso che certe ambiguità devono essere
> risolte nella primissima fase di compilazione di un template.
>
> Alcuni compilatori, evidentemente, posticipano tutte le decisioni al momento
> in cui il template viene istanziato. Questo non è conforme allo Standard, e
> può portare a istanziazioni che non dovrebbero essere consentite.
>
> Non so perché, invece, GCC compili quel codice se si aggiunge lo 'using'.
> Non trovo ragioni valide, e -come ho detto- tendo a credere che sia un
> fatto accidentale.
quello che mi lascia perplesso è che boost::tuple faccia conto su
questo comportamento non standard dei compilatori...
http://www.boost.org/doc/libs/1_35_0/libs/tuple/doc/tuple_users_guide.html#accessing_elements
Marco
Scusami, non capisco il tuo commento. La sintassi senza la keyword
"template" è prefettamente legale, a condizione che l'oggetto sia di un
tipo ben preciso, nel senso che non sia (o non dipenda da) un parametro di
un template. Vale in sostanza lo stesso principio della keyword "typename":
se non si tratta di un "dependent name", non bisogna usarla.
Max
certo hai ragione
non avevo colto appieno il "dettaglio essenziale"
> Sì, però, poiché la mia classe è templatizzata proprio sul tipo a cui viene
> applicato 'get', quel nome è un "dependent name".
messa così la cosa effettivamente non capisco cosa cambi al
compilatore sapere che siamo nel namespace boost
sono io programmatore nella definizione del template for_each_impl che
devo "chiedere esplicitamente" che il tipo Tuple abbia un template
method di nome "get"
giusto?
ho capito bene il punto oppure continua a sfuggirmi qualcosa?
se ho capito bene non sono comunque in grado di rispondere al tuo
dubbio
perchè dovrebbe essere necessario "using namespace boost"?
in effetti boost::tuple è il tipo effettivo su cui viene istanziato il
template
il fatto che per il gcc l'uso della direttiva "using namespace boost"
faccia differenza sembra confermare la tua ipotesi:
il compilatore attende una fase successiva, nella quale ha maggiori
informazioni, per mappare l'identificatore "get" sul metodo
"tuple::get"
a quel punto è ovviamente anche in grado di dedurre che "get" è un
template method e non un membro o un tipo
ciao,
Marco
Giusto. (Sempre che io non stia prendendo una cantonata; ogni tanto mi
càpita.)
>
> perchè dovrebbe essere necessario "using namespace boost"?
>
Infatti, secondo me è un effetto accidentale di qualche dettaglio
implementativo del GCC.
Con o senza 'using', il codice non è legale se non si aggiunge 'template'.
Perciò entrambi i compilatori -VC2005 e GCC4- non rispettano lo standard
in questo aspetto. (Credo.)
Max