Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in /home/www/novacisko.cz/subdomains/bredy/init.php on line 11

Warning: mysql_connect(): Headers and client library minor version mismatch. Headers:50562 Library:100020 in /home/www/novacisko.cz/subdomains/bredy/init.php on line 11

Warning: Cannot modify header information - headers already sent by (output started at /home/www/novacisko.cz/subdomains/bredy/init.php:11) in /home/www/novacisko.cz/subdomains/bredy/index.php on line 38
Jak předělat dvou-parametrovou šablonu na jedno-parametrovou - Bredyho blog - Ondřej Novák
Bredyho blog - Ondřej Novák

Jak předělat dvou-parametrovou šablonu na jedno-parametrovou

Popis jednoduchého triku


Už je to delší čas, co jsem na tomhle blogu ukazoval způsob, jak deklarovat šablonu, která jako svůj parametr vyžaduje šablonu (viz: Šablona jako parametr šablony). Použití takového zápisu může často zjednodušit zapisování komplikovaných šablon mající dlouhý rozvoj jen díky tomu, že do parametrů se doplní něco komplikovaného. Někdy dokonce ani nemáme jinou možnost, pokud parametry dodané šablony "vytvoří" až hostitelská šablona.

template < template < class > class MojeSablona >
class HostitelskaSablona {
public:
typedef Foo<... neco hrozne komplikovaneho...> ParamFoo;
typedef MojeSablona<ParamFoo> Bar;

Bar member;
}

Je vidět, že proměnná member je typu Bar, který vznikl až na základě informací dostupné hostitelské šabloně. Bez použití šablony jako parametru bysme velice obtížně vymýšleli parametry šablony MojeŠablona.

Tento způsob deklarace však může přinést komplikace v případě použití šablon s jiným počtem parametrů... kdy jeden z parametrů budeme chtít nechat volitelný z vnějšku (například programátorem). Typicky, pokud máme šablonu s "traits". V následujícím příkladě se budeme snažit "napasovat" dvou-parametrovou šablonu, do HostitelskaSablona

template < class T, class Traits >
class SablonaSTraits;

HostitelskaSablona<SablonaSTraits> x;
//CHYBA: Nesprávný počet parametrů šablony SablonaSTraits

Nepomůže nám ani použití "default" hodnoty pro Traits

template < class T, class Traits = DefaultTraits<T> >;
class SablonaSTraits;

HostitelskaSablona < SablonaSTraits > x;
//CHYBA: Nesprávný počet parametrů šablony SablonaSTraits

Jednorázovým řešením je podědit speciální šablonu, která již bude mít Traits dosazené

template < class T, class Traits >;
class SablonaSTraits;
template < class T >
class SpecialniSablona: public SablonaSTraits<T, DefaultTraits>
{
public:
...
}

HostitelskaSablona<SpecialniSablona> x;
//v pořádku

Tohle řešení je dobré, ale má několik zádrhelů.

  1. Musíme nadeklarovat všechny konstruktory ve SpecialniSablona, nebo aspoň ty, které budeme potřebovat. Můžeme si pomoci i použitím kopírovacího konstruktoru nebo kopírovat předka. Pro jeden případ to není velký zádrhel, ale v kombinaci s bodem 2 se to ukáže jako problém.
  2. Pokud máme variant s druhým parametrem víc (vícero Traits), budeme muset pro každý Traits vytvořit speciální šablonu. Pokud těch Traits máme řádově desítky, upíšeme se k smrti. A pokud budeme chtít obecné, upíše se k smrti ten, který naši šablonu bude chtít používat.

Existuje vůbec ještě jiný způsob, jak předělat dvou-parametrovou šablonu na jedno-parametrovou? Jeden bych v záloze měl. A dokonce mi umožní při dosazování šablony volit Traits jako parametr.

template < class Traits >
class KolekceSablonSTraits {
public:
template < class T >
class Sablona: public SablonaSTraits< T,Traits >
{
public:
....
};
}

HostitelskaSablona< KolekceSablonSTraits<NejakaTraits>::Sablona > x;
//v pořádku

Princip je zřejmý. Rozdělit dvou-(více-)parametrové šablony na dvě části. Ve vnější části máme definované parametry, které chceme dosadit při použití šablony. Vnitřní část pak má definované parametry, které dodá hostitelská třída. Výsledkem je třída, která dědí původní třídu. Zbyla nám pouze nutnost deklarovat všechny konstruktory. Budeme to ale dělat jen jednou a tak to není tolik práce. Ve standardu C++0x by snad dokonce mohla odpadnout i tato práce.

To je vše.

vytvořeno: 21.8.2009 08:27:20, změněno: 21.8.2009 08:37:47
Jsou informace v článku pro Vás užitečné?
  • ()
  • ()
  • ()
  • ()
  • ()
Nick nebo OpenID
Vzkaz
 
4.10.2009 12:19:51

Ondra openid

Mimochodem v C++ nelze udělat šablonu typedefu přímo, ale stejným trikem to jde nepřímo. Pokud máme šablonu Sablona<A,B>, pak udělat typedef s volitelným A a s pevným B se udělá takto:

template<typename A>
struct SablonaSPevnymB {
typedef Sablona<A,PevneB> T;
};

Reference je pak pomocí typename SablonaSPevnymB<X>::T

Doufám ale, že na C++0x už nebudeme čekat dlouho.
4.10.2009 12:16:04

Ondra openid

Ještě existuje jeden způsob a to pomocí typedefu

template < class Traits >
class KolekceSablonSTraits {
public:
template < class T >
struct SablonaDef
{
typedef SablonaSTraits< T,Traits > Sablona
};
}

Problém je, že tam, kde chceme pak tenhle zápis použít musí hostitelská třída vyzvedávat konečnou třídu jako

typename MojeSablona<X>::Sablona

Tedy nemůže použít přímo ten typ, ale až ten typedef. Ovšem vyřeší to problém konstruktorů, Nevýhodou je zase to, že typedef je pouze alias, takže některé překladače pak mohou mít problém s délkou názvu typu, který může být velice komplikovaný.
2.10.2009 16:14:57

Sten

Ty konstruktory v KolekceSablonSTraits<NejakaTraits>::Sablona bych taky udělal jako šablony (třeba od nula do osmi parametrů) a kompilátor nechal postarat se o to, aby výsledek dával smysl. (Tohle je hint pro ty, kteří se s konstruktory vypisují ručně)

Podobné články

Multiple Interface a Instance Factory

Používáme-li v C++ dědičnost a polymorfizmus, často řešíme problém, jak psát operace nad objekty, jejiž implementace se liší podle typu potomka, bez toho aniž bysme zasáhli do Base třídy.

Dědičnost šablon, CRTP a Invoker

OOP prvky lze používat i při generickém programování pomocí šablon. Dědit šablony je snadné, podívejme se i na polymorfické šablony.

Jak na paralelní překlad ve VC8

Máte doma procesor s DualCore? Nebo snad máte víc jader? A vadí vám, že VC8 Express moc dobře nevyužije tuto vlastnost? Závidíte linuxakům příkaz make -jN? Mám pro Vás dobrou zprávu.

Jogr nebrat!

Chcete si koupit levnou USB flashku (klíčenku). Tak hlavně nekupujte Jogra. Ztráta dat je na cestě. (negativní reference)

Šablony a kvalifikátor const - Jak správně konstruovat šablony s ukazatelem?

Chytrý ukazatel nebo pole? Vždy se jedná o šablonu, která obsahuje ukazatel na T. Přitom je třeba postihnout chování const
Reklama: