Šablony v C++Upravit

Hlavní článek: Šablona (C++)

C++ používá šablony umožňují obecných programovacích technik. Standardní knihovna C++ obsahuje standardní knihovnu šablon nebo STL, která poskytuje rámec šablon pro běžné datové struktury a algoritmy. Šablony v C++ mohou být také použity pro metaprogramování šablon, což je způsob předběžného vyhodnocení některých kódů v době kompilace, spíše než v době běhu. Použití šablony specializace, C++ šablony jsou považovány Turing kompletní.,

technické overviewEdit

existují dva druhy šablon: funkční šablony a šablony tříd. Šablona funkce je vzor pro vytváření běžných funkcí založených na parametrizačních typech dodávaných při instanci. Například standardní knihovna šablon C++ obsahuje funkční šablonu max (x, y), která vytváří funkce, které vracejí buď x nebo y, podle toho, co je větší., max() může být definován takto:

template <typename T>T max(T x, T y) { return x < y ? y : x;}

Zaměření této funkce šablony, instantiations s konkrétními typy, může být nazýván jen jako obyčejná funkce:

std::cout << max(3, 7); // Outputs 7.

kompilátor zkoumá argumenty používané pro volání max a určuje, že toto je volání max(int, int)., To pak vytvoří instanci verze funkce, kde parametrické typ T je int, což odpovídá následující funkce:

int max(int x, int y) { return x < y ? y : x;}

To funguje, zda argumenty x a y jsou celá čísla, řetězce, nebo jakýkoli jiný typ, pro který je výraz x < y, je rozumné, nebo více specificky, pro každý typ, pro který operátor< je definována. Společná dědičnost není potřebná pro sadu typů, které lze použít, a proto je velmi podobná kachnímu psaní., Program definovat vlastní datový typ, můžete použít operátor přetížení definovat význam < pro tento typ, což umožňuje jeho použití s max() funkce šablony. Sice se to může zdát menší přínos v této izolované, například, v kontextu komplexní knihovna jako STL, to umožňuje programátorovi, aby si rozsáhlou funkčnost pro nový datový typ, jen tím, že definuje několik operátorů., Pouze definování < umožňuje typ pro použití s standardní sort(), stable_sort(), a binary_search() algoritmy, nebo se dát dovnitř datových struktur, jako jsou sady, hromady, a asociativní pole.

c++ šablony jsou v době kompilace zcela bezpečné. Jako demonstraci standardní typový komplex nedefinuje operátor<, protože na složitých číslech neexistuje přísná objednávka. Proto max (x, y) selže s chybou kompilace, pokud x a y jsou složité hodnoty., Podobně jiné šablony, které se spoléhají na <, nelze použít na složitá data, pokud není poskytnuto srovnání (ve formě funktoru nebo funkce). Např.: komplex nelze použít jako klíč pro mapu, pokud není poskytnuto srovnání. Bohužel, kompilátory historicky generují poněkud esoterické, dlouhé a neužitečné chybové zprávy pro tento druh chyby. Zajištění toho, aby určitý objekt dodržoval protokol metody, může tento problém zmírnit. Jazyky, které používají porovnat namísto < lze také použít komplexní hodnoty jako klíče.,

druhý druh šablony, šablona třídy, rozšiřuje stejný koncept na třídy. Třída šablona specializace je třída. Šablony tříd se často používají k vytváření generických kontejnerů. Například STL má propojený kontejner seznamu. Chcete-li vytvořit propojený seznam celých čísel, zapíše seznam<int>. Seznam řetězců je označen seznam<string>. Seznam obsahuje sadu standardních funkcí, které pracují pro všechny kompatibilní parametrizační typy.,

specializace Šablonedit

výkonnou vlastností šablon C++je specializace šablon. To umožňuje poskytovat alternativní implementace na základě určitých charakteristik parametrizovaného typu, který je instanciován. Specializace šablon má dva účely: umožnit určité formy optimalizace a snížit bloat kódu.

například zvažte funkci šablony řazení (). Jednou z primárních činností, které taková funkce provádí, je výměna nebo výměna hodnot ve dvou pozicích kontejneru., Pokud jsou hodnoty vysoké (z hlediska počtu bajtů je potřeba ukládat každé z nich), pak je to často rychlejší, aby nejprve vytvořit samostatný seznam ukazatelů na objekty, třídit ty ukazatele, a pak stavět konečné seřazené sekvenci. Pokud jsou hodnoty poměrně malé, je obvykle nejrychlejší vyměnit hodnoty na místě podle potřeby. Kromě toho, pokud je parametrizovaný Typ již nějakého typu ukazatele, není třeba vytvářet samostatné pole ukazatele., Specializace šablon umožňuje tvůrci šablon psát různé implementace a specifikovat vlastnosti, které musí mít parametrizovaný Typ(Y) pro každou implementaci, která má být použita.

Na rozdíl od funkčních šablon mohou být šablony tříd částečně specializované. To znamená, že alternativní verze kódu šablony třídy může být poskytnuta,pokud jsou známy některé parametry šablony, přičemž ostatní parametry šablony jsou obecné., To může být použit, například, pro vytvoření výchozí implementace (primární zaměření), která předpokládá, že kopírování parametrické typ je drahé, a pak vytvořit částečné specializace na typy, které jsou levné kopírovat, čímž se zvyšuje celková účinnost. Klienti takové třídy šablony stačí použít oborů, aniž by museli vědět, zda kompilátor používá primární zaměření nebo některé dílčí specializace v každém případě., Třída šablony mohou být také plně specializované, což znamená, že alternativní implementace může být za předpokladu, kdy všechny parametrické typy jsou známy.

Výhody a disadvantagesEdit

použití šablon, jako max() funkce, které byly dříve obsazena funkce-jako preprocesor makra (dědictví programovací jazyk C). Například, tady je možné max() makro:

#define max(a,b) ((a) < (b) ? (b) : (a))

Makra jsou rozbaleny tím, preprocesor, kompilace před řádné; šablony jsou rozšířeny v době kompilace., Makra jsou vždy rozšířena inline; šablony lze také rozšířit jako inline funkce, když to kompilátor považuje za vhodné. Obě funkční makra a funkční šablony tedy nemají režii běhu.

šablony se však pro tyto účely obecně považují za zlepšení oproti makrům. Šablony jsou bezpečné pro typ. Šablony se zabránilo některé běžné chyby v kódu, který dělá těžké použití funkce, jako makra, jako je hodnocení parametrů s vedlejšími účinky dvakrát. Snad nejdůležitější je, že šablony byly navrženy tak, aby byly použitelné na mnohem větší problémy než makra.,

k Dispozici jsou čtyři základní nevýhody použití šablon: podporované funkce, kompilátor podporu, chudé chybové zprávy a kód nafouknutí:

  1. Šablony v C++ chybí mnoho funkcí, které činí jejich provádění a jejich využití v jednoduché, jak často nemožné. Místo programátoři muset spoléhat na složité triky, které vede k nafouklé, těžké pochopit a těžko udržovat kód. Aktuální vývoj v C++ normy zhoršit tento problém tím, že těžké použití těchto triků a budování mnoho nových funkcí pro šablony na nich nebo s nimi v mysli.,
  2. mnoho kompilátorů má historicky špatnou podporu šablon, takže použití šablon může učinit kód poněkud méně přenosným. Podpora může být také špatná, pokud je kompilátor C++ používán s linkerem, který není C++vědom, nebo při pokusu o použití šablon přes hranice sdílené knihovny. Většina moderních kompilátorů má však nyní poměrně robustní a standardní podporu šablon a nový standard C++, C++11, tyto problémy dále řeší.
  3. téměř všechny kompilátory vytvářejí matoucí, dlouhé nebo někdy neužitečné chybové zprávy, když jsou chyby detekovány v kódu, který používá šablony., To může ztěžovat vývoj šablon.
  4. Konečně, použití šablon vyžaduje kompilátor generovat samostatnou instanci šablony třídy nebo funkce pro každou variantu parametry typu používá s to. (To je nezbytné, protože typy v C++ nejsou všechny stejné velikosti a velikosti datových polí jsou důležité pro fungování tříd.) Takže nerozlišující použití šablon může vést k nafouknutí kódu, což má za následek příliš velké spustitelné soubory., Nicméně, rozumné využívání šablony specializace a odvození může výrazně snížit takový kód udit v některých případech:

Takže, můžete odvození být použity ke snížení problém kód replikovány, protože šablony se používají? To by znamenalo odvození šablony z běžné třídy. Tato technika se ukázala jako úspěšná při omezování nafouknutí kódu v reálném použití. Lidé, kteří nepoužívají takovou techniku, zjistili, že replikovaný kód může stát megabajty kódového prostoru i v programech střední velikosti.,

— Bjarne Stroustrup, Design a Vývoj C++, 1994

extra instantiations vytvořené šablony mohou také způsobit ladicí programy mají potíže pracuje elegantně s šablony. Například, nastavení, ladění zarážku do šablony ze zdrojového souboru může buď chybět nastavení zarážky v aktuální instance požadované nebo může nastavit zarážku na každém místě šablona je vytvořena instance.,

Také, protože kompilátor musí provádět makro-jako expanze šablon a vytvářet různé případy, z nich v době kompilace, provádění zdrojového kódu šablony třídy nebo funkce, musí být k dispozici (např. zahrnuty v záhlaví) kód pomocí to. Templované třídy nebo funkce, včetně velké části standardní knihovny šablon (STL), pokud nejsou zahrnuty do hlavičkových souborů, nelze kompilovat. (To je na rozdíl od non-templovaný kód, který může být kompilován do binární, poskytuje pouze soubor deklarace záhlaví pro kód, který jej používá.,) To může být nevýhodou vystavením prováděcího kódu, který odstraní některé abstrakce a mohl by omezit jeho použití v projektech s uzavřeným zdrojem.

šablony v DEdit

programovací jazyk D podporuje šablony založené na návrhu na C++.,Většina C++ šablony, styly, bude provádět v průběhu Vývoje beze změny, ale přidává některé další funkce:

  • parametry Šablony v D nejsou omezeny jen typy a primitivní hodnoty, ale také umožňují libovolné kompilace-time hodnoty (jako řetězce a struct literály), a aliasů do libovolné identifikátory, včetně jiné šablony nebo šablony instantiations.
  • omezení šablony a statické prohlášení if poskytují alternativu k selhání substituce C++není mechanismus chyby (SFINAE), podobný koncepcím c++.
  • is(…,) výraz umožňuje spekulativní instanci ověřit vlastnosti objektu v době kompilace.
  • auto klíčové slovo a typeof výraz povolit typ inference pro deklarace proměnných a funkcí, návratové hodnoty, což umožňuje „Voldemort types“ (typy, které nemají globální jména).

Šablony v D používat jinou syntaxi než v C++: vzhledem k tomu, že v C++ šablony parametry jsou zabalené v úhlových závorkách (Template<param1, param2>),D používá vykřičník a závorky: Šablony!(param1, param2).,Tím se zabrání problémům s analýzou C++ v důsledku nejednoznačnosti s operátory srovnání.Pokud existuje pouze jeden parametr, mohou být závorky vynechány.

Obvykle, D kombinuje výše uvedené vlastnosti, aby poskytnout kompilace-time polymorfismus pomocí rys na bázi generické programování.,Například, vstupní rozsah je definován jako typ, který splňuje kontroly prováděné isInputRange, které je definováno takto:

funkce, která přijímá pouze vstupní rozsahy lze pak použít výše uvedené šablony do šablony omezení:

auto fun(Range)(Range range) if (isInputRange!Range){ // ...}
Kód generationEdit

kromě template metaprogramming, D také nabízí několik funkcí, které umožňují kompilace-time generování kódu:

  • import vyjádření umožňuje čtení souboru z disku a pomocí jeho obsah jako řetězec výrazu.,
  • compile-time reflection umožňuje výčet a kontrolu prohlášení a jejich členů během kompilace.
  • uživatelem definované atributy umožňují uživatelům připojit libovolné identifikátory k deklaracím, které pak lze vyčíslit pomocí reflexe času kompilace.
  • Compile-Time function Execution (CTFE) umožňuje podmnožinu D (omezeno na bezpečné operace), které mají být interpretovány během kompilace.
  • String mixins umožňují vyhodnocování a sestavování obsahu řetězcový výraz jako D kód, který se stává součástí programu.,

kombinace výše uvedeného umožňuje generování kódu na základě existujících deklarací.Například, D serializace rámců lze vyjmenovat typ členů a vytvářet specializované funkce pro každý serializovaný typeto provést serializace a deserializace.Uživatelem definované atributy by mohly dále naznačovat pravidla serializace.

provedení importního výrazu a doby kompilace také umožňuje efektivní implementaci jazyků specifických pro doménu.,Například, vzhledem k tomu, funkce, která vezme řetězec obsahující HTML šablonu a vrátí ekvivalent D zdrojový kód, je možné jej použít následujícím způsobem:

Genericity v EiffelEdit

Generické třídy byly součástí Takových od původní metody a jazykové konstrukce. Nadace publikace Eiffel, používat termín obecnost popsat tvorbu a používání generických tříd.

základní / neomezená genericityEdit

generické třídy jsou deklarovány s jejich názvem třídy a seznamem jednoho nebo více formálních generických parametrů., V následujícím kódu, class LIST má jeden formální parametr obecné G

formální generické parametry jsou zástupné symboly pro libovolné názvy tříd, které budou dodávány, kdy deklarace generické třídy je vyroben, jak je znázorněno na dva obecné derivace níže, kde ACCOUNT DEPOSIT jsou jiné názvy tříd. ACCOUNT DEPOSIT jsou považovány za skutečné obecných parametrů, jako poskytují skutečné názvy tříd nahradit G při skutečném použití.,

 list_of_accounts: LIST -- Account list list_of_deposits: LIST -- Deposit list

v rámci systému typu Eiffel, ačkoli třída LIST je považována za třídu, nepovažuje se za typ. Za typ se však považuje generická derivace LIST , jako je LIST .

Omezeny genericityEdit

Pro seznam třídy je uvedeno výše, skutečný parametr obecné nahrazení G může mít jakékoliv jiné dostupné třídy., Chcete-li omezit sadu tříd, ze kterých lze zvolit platné skutečné obecné parametry, lze zadat obecné omezení. V deklaraci třídy SORTED_LIST níže, obecné omezení velí, že jakékoliv platné aktuální generický parametr bude třída, která dědí z třídy COMPARABLE. Obecné omezení zajišťuje, že prvky SORTED_LIST lze ve skutečnosti třídit.,

class SORTED_LIST 

Generika v JavaEdit

Hlavní článek: Generika v Javě

Podpora pro generika, nebo „kontejnery-of-type-T“ byl přidán programovací jazyk Java, v roce 2004 jako součást J2SE 5.0. V Javě jsou generika kontrolována pouze v době kompilace pro správnost typu. Obecné informace o typu jsou poté odstraněny procesem zvaným type erasure, aby byla zachována kompatibilita se starými implementacemi JVM, což je za běhu nedostupné., Například seznam<řetězec > je převeden na seznam raw typu. Kompilátor vloží Typ odlitky převést prvky na typ řetězce, když jsou načteny ze seznamu, snížení výkonu ve srovnání s jinými implementacemi, jako jsou šablony c++.

Genericity .NET Upravit

Generika byly přidány jako součást .NET Framework 2.0 v listopadu 2005, na základě výzkumu prototyp od společnosti Microsoft Výzkum začal v roce 1999. I když podobné generiky v Javě, .,Net generics neplatí Typ vymazání, ale implementovat generika jako mechanismus první třídy v běhu pomocí reifikace. Tato volba designu poskytuje další funkce, jako je například umožňuje odraz při zachování generické typy, jakož i zmírnění některých omezení výmaz (např. být schopen vytvořit generické pole). To také znamená, že neexistuje žádný výkon hit z runtime odlitků a normálně drahé boxerské konverze., Když se jako obecné argumenty používají primitivní a hodnotové typy, získají specializované implementace, což umožňuje efektivní generické sbírky a metody. Stejně jako v C++ a Java, vnořené generické typy, jako Dictionary<string, List<int>> jsou platné typy, nicméně se doporučuje proti pro členské podpisy v kódu analýzy navrhnout pravidla.

.,NET umožňuje šest druhů obecný typ omezení použití, kde klíčové slovo včetně omezení generických typů musí být hodnota typy, třeba třídy, konstruktory, a implementovat rozhraní. Níže je příklad s rozhraním omezení:

MakeAtLeast() metoda umožňuje provoz na pole, s prvky obecné typ T. metoda je typ omezení označuje, že metoda je použitelná pro jakýkoli typ T, který implementuje generické IComparable<T> rozhraní., Tím je zajištěna chyba času kompilace, pokud je metoda volána, pokud Typ nepodporuje srovnání. Rozhraní poskytuje obecnou metodu CompareTo (T).

výše uvedená metoda by také mohla být napsána bez generických typů, jednoduše pomocí generického typu pole. Nicméně, protože pole jsou contravariant, lití by neměly být bezpečný typ a kompilátor by být schopen najít některé možné chyby, které by jinak být chycen při použití generických typů. Kromě toho by metoda musela místo toho přistupovat k položkám pole jako k objektům a vyžadovala by odlévání pro porovnání dvou prvků., (Pro typy hodnot jako typy, jako int to vyžaduje boxu konverze, i když to lze obejít pomocí Comparer<T> třídy, jako je tomu ve standardní třídy kolekce.)

pozoruhodné chování statických členů v generické třídě. NET je statická členská instance na typ běhu (viz příklad níže).

Genericity v DelphiEdit

Delphi je Object Pascal dialekt získal generik v Delphi 2007 vydání, zpočátku pouze s (nyní skončený) .,Net kompilátor před přidáním do nativního kódu ve verzi Delphi 2009. Sémantika a schopnosti generik Delphi jsou do značné míry modelovány na ty, které měly generiky v. NET 2.0, i když implementace je z nutnosti zcela odlišná. Zde je více či méně přímý překlad prvního příkladu C# uvedeného výše:

jako u C#, metody i celé typy mohou mít jeden nebo více parametrů typu. V příkladu je TArray generický Typ (definovaný jazykem) a MakeAtLeast generickou metodou., Dostupná omezení jsou velmi podobná dostupným omezením v C#: jakýkoli typ hodnoty, jakákoli třída, konkrétní třída nebo rozhraní a třída s parametrným konstruktorem. Vícenásobná omezení působí jako unie doplňkových látek.

obecnost ve volném Pascaleditu

Volný Pascal implementoval generika před Delphi a s různou syntaxí a sémantikou. Od verze FPC 2.6.0 je však syntaxe ve stylu Delphi k dispozici při použití jazykového režimu {$mode Delphi}. Svobodní programátoři Pascalu jsou tedy schopni používat generika v jakémkoli stylu, který upřednostňují.,

Delphi a Free Pascal příklad:

Funkční languagesEdit

Genericity v HaskellEdit

typ třídy mechanismus Haskell podporuje generické programování.Šest předdefinovaných tříd typů v Haskell (včetně Eq, typů, které lze porovnat pro rovnost, a ukázat, typy, jejichž hodnoty mohou být vykresleny jako řetězce) mají zvláštní vlastnost podpory odvozených instancí., To znamená, že programátor, kterým se definuje nový typ se může stát, že tento typ je příklad jednoho z těchto zvláštní typ třídy, bez zajištění implementace metody třídy, jak je obvykle nutné při deklarování třídy instance. Všechny potřebné metody budou „odvozeny“ – tedy konstruovány automaticky-na základě struktury typu.,Například, následující prohlášení typu binární stromy uvádí, že to má být instance třídy Eq a Show:

data BinTree a = Leaf a | Node (BinTree a) a (BinTree a) deriving (Eq, Show)

Tento výsledky v rovnosti funkce (==) a řetězec reprezentace funkce (zobrazit) je automaticky definováno pro každý typ formuláře BinTree T za předpokladu, že T sám podporuje tyto operace.,

podpora pro odvozené instance Eq a Show dělá jejich metody == a ukázat obecné, kvalitativně odlišným způsobem, než para-metricky polymorfní funkce: tyto „funkce“ (přesněji, typ-indexovány rodiny z funkce) může být aplikován na hodnoty různých typů, a i když se chovají odlišně pro každý argument typ, trochu pracovat, je potřeba přidat podporu pro nový typ. Ralf Hinze (2004) ukázal, že podobný efekt lze dosáhnout u uživatelsky definovaných tříd typů určitými programovacími technikami., Jiní vědci navrhli přístupy k tomuto a dalším druhům obecnosti v kontextu Haskell a rozšíření Haskell (diskutováno níže).

PolyPEdit

PolyP byl první generický programovací jazyk rozšíření Haskell. V polypu se generické funkce nazývají polytypické. Jazyk zavádí speciální konstrukci, ve které lze tyto polytypické funkce definovat pomocí strukturální indukce nad strukturou funkčního vzoru běžného datového typu. Pravidelné datové typy v polypu jsou podmnožinou datových typů Haskell., Pravidelný datový typ t musí mít typ * → *, a pokud je formální argument typu v definici, pak všechna rekurzivní volání do t musí mít tvar t a. Tato omezení vyloučit vyšší-kinded datové typy stejně jako vnořené datové typy, kde rekurzivní volání jsou jinou formou.Narovnat funkce v PolyP je zde uveden jako příklad:

Obecné HaskellEdit

Generic Haskell je další rozšíření k Haskell, vyvinutý na Univerzitě v Utrechtu v Nizozemí., Rozšíření, která poskytuje, jsou:

  • hodnoty indexované typem jsou definovány jako hodnota indexovaná nad různými konstruktory typu Haskell (jednotka, primitivní typy, součty, produkty a konstruktory typu definované uživatelem). Kromě toho můžeme také určit chování typově indexovaných hodnot pro konkrétní Konstruktor pomocí případů konstruktoru a znovu použít jednu obecnou definici v jiném pomocí výchozích případů.

výsledná hodnota indexovaná typem může být specializována na jakýkoli typ.

  • druhově indexované typy jsou typy indexované přes druhy, definované zadáním případu pro oba * a k → k‘., Instance se získají použitím druhu indexovaného typu na určitý druh.
  • obecné definice lze použít jejich použitím na typ nebo Druh. Tomu se říká generická aplikace. Výsledkem je typ nebo hodnota, v závislosti na druhu obecné definice.
  • generická abstrakce umožňuje definovat obecné definice abstrakcí parametru typu (daného druhu).
  • Type-indexed typy jsou typy, které jsou indexovány přes konstruktory typu. Ty mohou být použity k poskytnutí typů více zapojených generických hodnot., Výsledné typy indexovaných typů mohou být specializovány na jakýkoli typ.

Jako příklad, rovnost fungovat v Generic Haskell:

CleanEdit

Vyčistěte nabízí generické programování založené PolyP a generic Haskell jako podporované GHC>=6.0. Parametrizuje podle druhu jako ty, ale nabízí přetížení.

Ostatní jazykyedit

rodina programovacích jazyků ML podporuje generické programování pomocí parametrického polymorfismu a generických modulů nazývaných funktory.,Oba standardní ML a OCaml poskytují funktory, které jsou podobné šablonám třídy a generickým balíčkům Ada. Syntaktické abstrakce schématu mají také souvislost s obecností-jedná se ve skutečnosti o supersetu šablon à la c++.

modul Verilog může mít jeden nebo více parametrů, ke kterým jsou přiřazeny jejich skutečné hodnoty při instalaci modulu. Jedním z příkladů je obecné pole registru, kde je šířka pole dána parametrem., Takové pole, v kombinaci s generickým vektorem drátu, může vytvořit obecný vyrovnávací paměť nebo paměťový modul s libovolnou šířkou bitů z jedné implementace modulu.

VHDL, odvozený od Ada, má také obecné schopnosti.