PDA

View Full Version : STL: Farsi un fuctor iota sofisticato(Cionci ,Marco invited)


verloc
04-05-2003, 09:46
Mi sono accorto che la STL non ha nello standard il comodo functor iota implementato dalla SGI
(serve a generare sequenze di numeri in container tipo vector,list etc)
quindi me ne sono fatto uno a mano.(Puo darsi che nella libreria boost ci sia già, ma sulla macchina di mio fratello
non l'avevo a disposizione).
Non esitate a proporre miglioramenti o segnalare anomalie (ve ne sarei grato) :)



template <class T>
class iota_gen {
public:
iota_gen(T start,T increment) : current(start) ,inc(increment) {}
T operator () () {T tmp= current;
current+=inc;
return tmp ;}
private:
T current;
T inc;
};

//Esempio di chiamata
...
vector <double> viota(10);
//riempie viota a partire da 0.0 aggiungendo 1.5 al precedente elemento
generate(viota.begin(),viota.end(), iota_gen<double>(0.0,1.5));
...


Lo sfizio ora sarebbe farne una versione che permette l'uso dei functor standard
(sottrazione,moltiplicazione,etc)per scegliere il modo in cui generare la sequenza e
non limitarlo all'addizione.

Siete capaci di farlo?Io al momento no. :(
Non è un fatto necessario per me (al momento) ,ma mi sembrava un quesito interessante. ;)


Un esempio d'uso?
suponete di avere la funzione x=f(y) non invertibile (o anche non facilmente invertibile).
Voi avete bisogno invece di calcolare y=f(x) in un certo intervallo Xa -Xb .
Un modo semplice è quello di approssimare y=f(x) con una poligonale.
Quindi generate un vettore di n coordinate yi a partire da Ya con un intervallo (Ya-Yb)/(n-1);
un altro vettore di n coordinate xi=f(yi).
A questo punto potete calcolare qualunque valore Yc(Xc) sfruttando i punti a disposizione.
Questo è il caso reale che è capitato a me :)

cionci
04-05-2003, 12:48
Originally posted by "verloc"

Lo sfizio ora sarebbe farne una versione che permette l'uso dei functor standard
(sottrazione,moltiplicazione,etc)per scegliere il modo in cui generare la sequenza e
non limitarlo all'addizione.
Potresti passargli un puntatore ad una funzione che prende 2 parametri...il valore corrente e quello dell'incremento...

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

template <class T>
class iota_gen {
public:
iota_gen(T start,T increment, T (*oper)(T cur, T inc) = default_op)
: current(start) ,inc(increment), op(oper) {}
T operator () () {T tmp = current;
current = op(current, inc);
return tmp;};
protected:
virtual T default_op(T cur, T incr) {return cur+incr;};
private:
T current;
T inc;
T (*op)(T st, T inc);
};

template <class T>
T molt(T current, T increment)
{
return current * increment;
}

vector <double> viota(10);
...
generate(viota.begin(),viota.end(), iota_gen<double>(0.1,1.5,molt));
...

verloc
04-05-2003, 13:00
Grazie Cionci ;)
avevo avuto l'idea dei puntatori ma non sapevo esattamente come farla.
la tua è una ottima idea.

La esamino meglio adesso.

Kleidemos
04-05-2003, 13:33
Originally posted by "cionci"




//....

T (*op)(T st, T inc);
//..



Mi spieghi come funz??
E un puntatore a funzione vero?

misterx
04-05-2003, 15:42
ma che cavolo di programma stai scrivendo??? :D

cionci
04-05-2003, 18:07
Originally posted by "Kleidemos"


Mi spieghi come funz??
E un puntatore a funzione vero?
I puntatori a funzioni hanno tipizzazione molto forte... Non solo è significativo il tipo di ritorno (T in questo caso), ma anche i parametri stessi...

T (*op)(T st, T inc);

T è il valore di ritorno...op è il nome del puntatore (c'è * davanti perchè è un puntatore)...il resto sono i parametri...
Non importa specificare i nome dei parametri formali (anzi non ha molto senso specificarli)... Meglio sarebbe scrivere così (anche io era da molto che non li usavo): T (*op)(T, T);

In pratica op può accettare solo funzioni il cui tipo di ritorno è T e i parametri sono 2 di entrambi di tipo T...

verloc
05-05-2003, 09:45
Dunque cionci,ieri ho fatto delle prove e
il compilatore mi segnala problemi solo quando lo chiamo senza specificare la funzione:

generate(viota.begin(),viota.end(), iota_gen<double>(1.0 , 2.0));

(non so;dovrebbe per come ho capito,richiamare default_op ma mi segnala questo:
Error E2034 riempvec.cpp 63: Cannot convert 'double (iota_gen<double>::*)(double,double)' to 'double (*)(double,double)' in function main()
Error E2151 riempvec.cpp 63: Type mismatch in default value for parameter 'oper' in function main() )

Comunque le tue indicazioni sono state preziosissime e ti spiego perchè.
1)Ho capito che l'operazione da usare doveva essere memorizzata nella classe.
2)Volevo usare i functor standard e dopo una mezz'ora di tentativi assurdi in cui
dichiaravo l'operazione come binary_function (non ti dico che usciva!)
3)Mi sono fermato a pensare,e ho concluso che plus divides etc in fondo non erano che degli
oggetti(la cosa non mi era proprio chiarissima) quindi bisognava dichiararli e usarli (un'altra mezz'ora per concludere che
dovevo metterli nel template :( )

template <typename T ,typename TFOO>
class iota_gen3 {
public:
iota_gen3(T start,T increment,TFOO tfo )
: current(start) ,inc(increment) ,foo(tfo) {}

T operator () () {T tmp = current;
current = foo(current, inc);
return tmp;};

private:
T current;
T inc;
TFOO foo;
};



In seguito solo dopo una grandisima botta di **** sono riuscito a fare la chiamata giusta
(perchè quando si tratta di template me ne vado subito e sempre nel pallone)


//Esempi di chiamata
generate(viota.begin(),viota.end(), iota_gen3<double ,multiplies<double> >(1.0,2.0,multiplies<double>()));
generate(viota.begin(),viota.end(), iota_gen3<double ,minus<double> >(10.0,1.0,minus<double>()));


Credimi ,quando ho visto che funzionava neanche io ci credevo :eek: :eek: :eek:
Vedi un pò tu se si può aggiustare qualcosa (la chiamata non è un esempio di leggibilità :D ).

Comunque grazie per avermi fatto vedere come si usa un puntatore a funzione in una classe.
Credo che l' 80 % del merito di iota_gen3 sia tuo. ;)
(Quanno ce vò ce vò :D )

A proposito:
Chiamare una funzione tramite puntatore(a funzione) è + veloce rispetto ad una normale?

Ps.scusate il papiello :)

verloc
05-05-2003, 09:54
Originally posted by "misterx"

ma che cavolo di programma stai scrivendo??? :D

seh...ridi tu.
Sto scrivendo la mia tesi,questo codice mi è servito realmente(leggi sopra
a cosa).

La morale di verloc sulla STL:
quando vedi per la prima certe funzioni,tu dici :
"Daiiiii ... a chi puo fregare di queste str*****e ?"
Poi arrivi ad incocciarle :) e allora scopri la loro potenza...

"Luke...non sottovalutare il lato oscuro della STL"
:)

cionci
05-05-2003, 19:30
Bene :)

Riguardo alla velocità... Direi proprio di no... Visto che bisogna andare ad accedere in memoria per recuperare l'indirizzo della funzione che altrimenti sarebbe calcolato automaticamente in fase di compilazione...

/\/\@®¢Ø
06-05-2003, 10:40
Vedo che avete gia' fatto tutto voi :D

Solo un paio di piccoli suggerimenti per la leggibilita'.
La prima e' quella di aggiungere un parametro di default per l'oggetto da utilizzare,

template <typename T ,typename TFOO>
class iota_gen3 {
public:
iota_gen3(T start,T increment,TFOO tfo [b]=TFOO()[/b] )
: current(start) ,inc(increment) ,foo(tfo) {}


Nei casi semplici questo accorcia la chiamata a

//Esempi di chiamata
generate(viota.begin(),viota.end(), iota_gen3<double ,multiplies<double> >(1.0,2.0));
generate(viota.begin(),viota.end(), iota_gen3<double ,minus<double> >(10.0,1.0));


Per i casi "complessi" (dove l'oggetto va costruito con parametri), io aggiungerei la seguente funzione:


template <typename T , typename TFOO>
iota_gen3<T,TFOO> mk_iota( T x , T y , TFOO z )
{
return iota_gen3<T,TFOO>(x,y,z);
}


Con questo puoi evitare un po- di parametri template, visto che verranno identificati automaticamente:


generate(viota.begin(),viota.end(), mk_iota(1.0,2.0, multiplies<double>() ));

o meglio ancora

multiplies<double> mul;
generate(viota.begin(),viota.end(), mk_iota(1.0,2.0,mul ));

verloc
06-05-2003, 12:09
Semplicemente Meraviglioso,Marco!

Non scherzo se dico che tu e Cionci date delle botte di progresso enormi
alle mie conoscenze di apprendista.

Sul serio,credetimi!
E' riconoscenza,non piaggeria!

Mercì :)

cionci
06-05-2003, 12:11
E' /\/\@®¢Ø il mago della STL ;) Io sono ancora un principiante :)