TechBlog cikkei
Osztály template csak meghatározott típusokkal
Mint már megszokhattátok tőlem, általában programozási ötletekért keresem fel a TechBlogot.
Ez most sincs másképp...
A nyelv C++
, a kérdés pedig, hogy tudok-e olyan osztály template-et csinálni, ami csak bizonyos típusokból engedi megcsinálni a template-et? Konkrétan, szeretnék egy olyan osztály template-et csinálni, ami csak double
vagy egy bizonyos saját típus (nevezzük mondjuk __CLPK_doublecomplex
nek) felett működik, mással nem.
Köszi a segítséget!
Hozzászólások
8Apocalypse KÖZÖS
Az álom törékeny, a vízió elhomályosulhat, ha nem tartod szíved egy biztos zugában.
UPi 2009.X.02 19:11
Arról írnál, hogy miért jó egy template osztályt korlátozni? Számomra dupla-plusz szükségtelennek tűnik, ha nem akarod, hogy int-re specializálódjon, akkor ne specializáld int-re...
SAdam 2009.X.02 20:16
Egyszerű. Van egy
Matrix
nevű osztályom, amire definiáltam az összes lehetséges operator overloading-ot, amire a számításaim során szükségem lehet, ezen kívül van egy rutin, ami kiadja a sajátértékeit, meg a bal- és jobboldali sajátvektorait. Ez aMatrix
osztály jelenleg komplex számok formájában (konkrétan, az általam említett__CLPK_doublecomplex
típusként) tárolja el magát a mátrixot.Most úgy adódott, hogy szükségem lenne egy valós mátrixot reprezentáló osztályra is. Ezért két lehetőségem van: vagy definiálok egy új osztályt, ahol a mátrix értékeit
double
ként tárolom, és szó szerint lemásolom az összes operator overloading-ot, amit csak csináltam (plusz átírom a sajátértékeket számító függvényt), vagy csinálok a már meglévő osztályból egy template osztályt, amit utána használhatokMatrix<double>
vagyMatrix<__CLPK_doublecomplex>
formában (ez utóbbi sokkal olvashatóbbá teszi a kódot, továbbá megkímél attól, hogy duplikálnom kelljen feleslegesen egy csomó kódot).Azért szeretném, ha mindenképp explicit definiálni tudnám azt a halmazt, amiből a mátrix készülhet, mert nem akarok olyat megengedni, hogy definiálni lehessen mondjuk
Matrix<bool>
, vagy valami hasonló hülyeséget, aminek semmi értelme. Ráadásul kipróbáltam, hogy ha "csak úgy" csinálok belőle egy template-et, akkor nem fog lefordulni a kód, mert nem fogja tudni, hogy egy általános T osztályra hogyan értelmezze azt, hogy mondjuk "return T + 2
", míg ha T explicit módon korlátozva van adouble
vagy__CLPL_doublecomplex
típusok valamelyikére, akkor a fenti kifejezést a fordítónak (legalábbis tippem szerint) mindenképp kell tudnia értelmezni.SAdam 2009.X.02 20:23
Bocs, most esett le, hogy tul. képp. mit kérdeztél. Szóval a válasz, hogy szeretném, ha a kód lefordulna. Jelenleg, ha csak úgy deklarálom az osztályom, hogy
akkor a fordító hibát dob, az előző levelemben ismeretett ok miatt. Szóval, az is jó, ha valaki tud adni egy tippet, hogy mit kell ahhoz csinálni, hogy a fordító "elhigyje" nekem, hogy a
T
osztály csak olyan dolgokból fog kikerülni, amiket valóban lehet összeadni, szorozni, satöbbi. Ha erre van megoldás, akkor persze már nem fogom akarni megszorítani az osztályt, hogy csakdouble
vagy__CLPK_doublecomplex
alapon lehessen definiálni...UPi 2009.X.02 20:34
Még mindig nem értem, hogy mi a probléma, ugyanis amíg nincs konkrét T, addig a fordító nem fordít neked a template-ből semmit. Vagyis, ha ezt írod:
template class valami {
T value;
public:
valami(T _value) : value(_value) {}
T multiplyByTen() { return T * 10; }
};
valami i(10); int j = i.multiplyByTen(); // Ez működik.
valami s("kutya"); string r = s.multiplyByTen(); // Ez nem fordul le, mert nincs string.operator*(int) függvény.
Magyarán, amíg nem csinálsz valamit, amitől olyan kód fordul, ami helytelen, addig nincs gond a template-tel. Vagyis még mindig nincs okod külön erőfeszítést tenned azért, hogy ne tudd példányosítani a template-et rossz paraméterrel: ezt a fordító megteszi helyetted.
UPi 2009.X.02 20:35
(Válaszképp erre)
Bocs, az előző kommentben
T multiplyByTen() { return _value * 10; }
akart lenni..SAdam 2009.X.02 20:38
(Válaszképp erre)
<blockquote> Még mindig nem értem, hogy mi a probléma, ugyanis amíg nincs konkrét T, addig a fordító nem fordít neked a template-ből semmit. Vagyis, ha ezt írod:
template <class T> class valami { T value; public: valami(T _value) : value(_value) {} T multiplyByTen() { return T * 10; } }; valami<int> i(10); int j = i.multiplyByTen(); // Ez működik. valami<string> s("kutya"); string r = s.multiplyByTen(); // Ez nem fordul le, mert nincs string.operator*(int) függvény.
Magyarán, amíg nem csinálsz valamit, amitől olyan kód fordul, ami helytelen, addig nincs gond a template-tel. Vagyis még mindig nincs okod külön erőfeszítést tenned azért, hogy ne tudd példányosítani a template-et rossz paraméterrel: ezt a fordító megteszi helyetted. </blockquote>
Akkor valamit elb*sztam... Nyüff. Nekifutok megint, és ha még mindig nem megy, akkor jelentkezem megint...
SAdam 2009.X.05 04:14
Na, két napi nekifutás után még mindig nem megy, de legalább kezd fény derengeni...
Szóval addig eljutottam, hogy a template-ekből fordítási időben készülnek el a konkrét osztályok, ezért ha fordítási időben rendelkezésre áll minden, akkor nincs gond, le fog fordulni a program, vagyis nem kell explicit módon megadnom, hogy miből engedem meg létrehozni a konkrét ojjektumot, mert a fordító úgyis jelez, ha hiba van.
Na most a problémám már csak az, hogy hogyan tudok "feltételes fordítást" csinálni annak alapján, hogy milyen típus alapján készült a template? Magyarul, vagy egy rutinom (konkrétan, az a rutin, ami a mátrix sajátértékeit számolja), ami más algoritmust kellene, hogy futtasson akkor, ha a mátrix komplex, mint akkor, ha a mátrix valós. Első blikkre a
dynamic_cast
paranccsal próbáltam megoldani a dolgot (úgy, hogy az eljárás elején definiáltam egyT
típusú változót, és tesztelem, hogy mivé tudom castolni, és ez alapján egy elágazás szerint csinálom a csinálnivalót), de ez egyrészt csúnya, másrészt valahogy nem akar működni, ugyanis a fordító már fordítási időben közli, hogy nem fog menni a castolás, ezért le sem fordítja a dolgot. Van erre valami szép módszer, hogy külön definiálni tudjam aMatrix<double>
és aMatrix<__CLPK_complex>
osztályok ugyanolyan nevű (legyen mondjukgetEigenValues()
) metódusát?A másik hasonlóan problémás dolog: lehet olyat csinálni, hogy definiáljam az általános
Matrix<T>
osztály egy eljárását valamilyenT
típusú paraméterrel, és külön megadhassam azt is, hogyT
-től függetlenül egydouble
paraméterre hogyan reagáljon ugyanez az eljárás? Konkrétan valami ilyesmire gondoltam:de ezt a fordító nem akarja megenni, merthogy ha
T
éppdouble
, akkor nem tudja eldönteni, hogy a két függvény közül melyiket használja. Másrészt viszont nem tudom, hogy tudnám biztosítani, hogy az értékadás operátor mindig működjöndouble
paraméterrel (komplex értékű mátrixot is lehet valós értékkel inicializálni elvégre).SAdam 2009.X.05 04:49
(Válaszképp erre)
<blockquote> Na most a problémám már csak az, hogy hogyan tudok "feltételes fordítást" csinálni annak alapján, hogy milyen típus alapján készült a template? Magyarul, vagy egy rutinom (konkrétan, az a rutin, ami a mátrix sajátértékeit számolja), ami más algoritmust kellene, hogy futtasson akkor, ha a mátrix komplex, mint akkor, ha a mátrix valós. Első blikkre a
dynamic_cast
paranccsal próbáltam megoldani a dolgot (úgy, hogy az eljárás elején definiáltam egyT
típusú változót, és tesztelem, hogy mivé tudom castolni, és ez alapján egy elágazás szerint csinálom a csinálnivalót), de ez egyrészt csúnya, másrészt valahogy nem akar működni, ugyanis a fordító már fordítási időben közli, hogy nem fog menni a castolás, ezért le sem fordítja a dolgot. Van erre valami szép módszer, hogy külön definiálni tudjam aMatrix<double>
és aMatrix<__CLPK_complex>
osztályok ugyanolyan nevű (legyen mondjukgetEigenValues()
) metódusát? </blockquote>UPDATE: Ezt a problémát közben sikerült megoldani, viszont fellépett helyette egy másik: sajnos ha szokásosan kiteszem egy külön fejléc file-ba a definíciókat, akkor a fordító nem találja a fordítandót, ezért muszáj voltam egy file-ba pakolni mindent. Így viszont az a hülye helyzet állt elő, hogy mivel a projektemben több file is include-olja a mátrixomat tartalmazó fejléc file-t, ezért gyönyörű
duplicate symbol
hibákat kapok linkeléskor. Tud valaki erre megoldást? (Amúgy fura, hogy ezzel ennyit bénázom, máskor általában fórumokon egész gyorsan fel lehet fogni dolgokat, de valahogy template-ügyben nem sikerül megtalálnom a megfelelő fórumokat, úgy tűnik...)