Evo pokusavao sam napraviti gui za x/o (tic tac toe) u fltk. Ideja: stavio sam 9 obicnih Fl_Button -s
koji treba da predstavljaju polja. Klikom na to dugme callback mijenja label tog dugmeta u x ili o. To je sve proslo ok. Unos se upisuje u 2d niz inicijaliziran na 0 da bi znali da li vec postoji unos. Sada me zanima kako da znam koje je dugme kliknuto npr.
±-+ ±-+ ±-+
| 1 | | 2 | | 3 |
±-+ ±-+ ±-+
.
.
. itd.
recimo klikom na dugme 1 treba da upise x ili oks (1,2) u niz[0][0]. Ja sam razmisljao da kao userdata
u callback svakog dugmeta stavim neki pokazivac ili referencu koji bi promjenio neku varijablu u main-u ili da citav niz pozovem kao argument. Buni me onaj (void*) u argumentu userdata. Na koji nacin se moze staviti pokazivac ili referenca na to mjesto. Ima li neko bolju ideju ili drugi pristup problemu ? Nadam se da je pitanje bilo razumljivo
Ovakvim postavljanjem pitanja mozes ocekivati samo odgovor od FLTK profesionalca sa kristalnom kuglom …
Ako odgovoris na sljedeca pitanja: Koji void* ? koji userdata ? u argumentu cega? I kopiras nam problematicni kod odgovor mozes ocekivati od svih ljudi koji rade sa c++om ili cak c-om
evo da pokusam malo jasnije napisati sta sam htio pitati
nrp:
jedna callback funkcija koja kao drugi arg prima void* userdata.
void but_cb( Fl_Widget* o, void* userdata ) {
.
.
cout<<int(userdata);
}
poziv callback funkcije
gdje ovaj drugi argument 12345 predstavlja userdata. Klikom na dugme u konzoli ce biti ispisano 12345.
Moje pitanje je bilo, da li se moze kao userdata staviti pokazivac ili referenca ? Buni me to sto callback funkcija kao drugi argument prima (void*).
Evo moje pitanje predstavljeno na jednom jednostavnom primjeru :
Imam napravljena tri Fl_Buttons. U mainu postoji varijabla int a=0. Klikom na dugme 1 varijabla a treba da poprimi vrijednost 1. Klikom na dugme 2, varijabla a poprima vrijednost 2. … dugme 3 varijabla a poprima vrijednost 3. Nadam se da sam sada bio bar malo jasniji.
int main(void)
{
int rezultat = 12345;
cout<<"Prije: "<<rezultat<<endl;
smanji_za_jedan(&rezultat);
cout<<"Poslije: "<<rezultat<<endl;
return 0;
}
void smanji_za_jedan(void *userdata)
{
int *rez = static_cast<int *>(userdata);
*rez -= 1;
}[/code]
Evo primjer koji sadrzi rjesenje tvog problema - pa ti skontaj …
Callback funkcija može primati i long kao parametar a ne samo void*. Void* je pointer na bilo šta (što ti olakšava prosljeđivanje najrazličitijih vrsta argumenata npr. možeš proslijediti pointer na neki Fl_Input koji je vezan za to dugme, samo ne zaboravi odraditi odgovarajući cast).
@testni_hamo2: tvoji odgovori su bili izuzetno helpful u ovom slučaju
Možel samo jedno (dobronamjerno) pitanje, zar se to ne može ljepše odraditi u C++? Prosljeđivanje parametara kao void* koristi se u C-u, ali se time gubi type safety.
Ja bi preporucio da kreiras neki svoj StateButton, izveden iz Fl_Button koji mijenja interno stanje (i label()) prilikom callback-a. Time ces izbjeci potrebu za 2d nizom.
Možel samo jedno (dobronamjerno) pitanje, zar se to ne može ljepše odraditi u C++?
Moglo bi se to rijesiti uz pomoc templatea ?
Naravno, http://sanel.linux.org.ba/fltk/
Prosljeđivanje parametara kao void* koristi se u C-u, ali se time gubi type safety.
Ah, suplja prica. gcc ionako u compile time-u “void” resolvira u odgovarajuci tip.
[quote=Sanel]> Prosljeđivanje parametara kao void* koristi se u C-u, ali se time gubi type safety.
Ah, suplja prica. gcc ionako u compile time-u “void” resolvira u odgovarajuci tip.[/quote]
Svejedno, gadno je
Upravo tako. void smanji_za_jedan(void *userdata)
{
int *rez = static_cast<int *>(userdata);
*rez -= 1;
}
Npr. ova funkcija prima ‘pointer na bilo sta’ tj. ‘void *’, nemoguce je da compiler pri compile time-u resolva tip; nebitno kako se pozove funkcija smanji_za_jedan, compajler nece praviti probleme sve dok je sintaksa korektna.
Npr. sljedeci dio koda je za vrijeme compiletime-a sasvim legalan
std::string a("abc");
smanji_za_jedan(&a);
std::cout << a << endl;
al ce se zato program srusiti pri runtime-u.
Ne resolvira GCC ništa
Ok, da malo pojasnim. Nacin resolviranja nije identican kao kod template-a zbog toga sto u ovom slucaju (void*) vrijedi samo nad pokazivacima (aka. pointer aliasing). U C99 je detaljno pojasnjeno sta moze biti alias za sta, mada od samih pocetaka void* je bio alias za pokazivac bilo kakvog tipa.
Ponekad se znalo desiti u 3.x seriji da za prototip “void foo(void*)” pri nekoj gresci javi “in void foo(int*) bla bla” ako se funkcija poziva samo sa int* tokom citavog koda.
ova funkcija prima ‘pointer na bilo sta’ tj. ‘void *’, nemoguce je da compiler pri compile time-u resolva tip
Gore pojasnjeno. Btw. kompajler uvijek moze da resolvira tip (izuzev slucajeva kad se jave viseznacni izrazi).
al ce se zato program srusiti pri runtime-u.
Ne vidim kakve veze ima tvoj primjer sa distinkcijom tipova.
Prica je krenula kada je Adis pomenuo type safety probleme, a oni su ilustrirani navedenim primjerom.
A zar nije prica krenula u pravcu resolviranja tipova ?
Pogotovo kad se autor koda potrudi da odrzi takvu reputaciju C+±a
Kao sto je neko rekao u kontekstu C+±a: “there is no safe shotgun”
Nisam imao osjecas da uopste postoji problem. Ukoliko si ti procijenio nivo mog (ne)shvatanja svrhe programskih jezika na osnovu dva one-linera, nemam zelju da te razuvjerim.
Za kraj mali zakljucak. Svrha jezika moze posluziti kao praktican izgovor za njegovu sustinsku neelegantnost.