Maler i C++Rediger

utdypende artikkel: Mal (C++)

C++ bruker maler for å aktivere generisk programmering teknikker. C++ Standard Biblioteket inkluderer Standard Template Library eller STL som gir et rammeverk av maler for vanlige datastrukturer og algoritmer. Maler i C++ kan også brukes for mal metaprogramming, som er en måte å pre-evaluere noen av koden på compile-time snarere enn å kjøre-time. Ved hjelp av malen spesialisering, C++ Maler er vurdert Turing fullstendig.,

Teknisk overviewEdit

Det er to typer maler: funksjon maler-og klasse-maler. En funksjon mal er et mønster for å lage vanlige funksjoner basert på parameterizing typer leveres når instansiert. For eksempel, C++ Standard Template Library inneholder funksjonen mal max(x, y) som skaper funksjoner som returnerer enten x eller y, som er større., max() kunne defineres som dette:

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

Spesialiseringer av denne funksjonen mal, instantiations med bestemte typer, kan bli kalt akkurat som en vanlig funksjon:

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

kompilatoren undersøker de argumentene som er brukt for å ringe max og fastslår at dette er en oppfordring til maks(int, int)., Det så instantiates en versjon av funksjon der parameterizing type T er int, noe som tilsvarer følgende funksjon:

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

Dette fungerer om argumenter x og y er heltall, strenger, eller noen andre type som uttrykk for x < y er fornuftig, eller mer spesifikt, for noen form for som operatør< er definert. Felles arv er ikke behov for et sett av typer som kan brukes, og så er det veldig lik duck å skrive., Et program til å definere et tilpasset datatype kan bruke operatør overbelastning å definere betydningen av < for den typen, dermed tillater bruk med maks () – funksjonen mal. Mens dette kan synes som en liten fordel i denne isolerte eksempel i sammenheng med et omfattende bibliotek som STL det lar programmereren å få omfattende funksjonalitet for en ny datatype, bare ved å definere et par operatører for det., Bare definere < lar en type som skal brukes med standard sorter(), stable_sort(), og binary_search() algoritmer eller å bli satt inne data strukturer som sett, hauger, og assosiative matriser.

C++ maler er helt type trygg på kompilere tid. Som en demonstrasjon, standard type kompliserte ikke angi < operatør, fordi det er ingen streng ordre om komplekse tall. Derfor, max(x, y) vil mislykkes med en kompileringsfeil, hvis x og y er komplekse verdier., Likeledes, andre maler som er avhengige av < kan ikke brukes til komplekse data, med mindre en sammenligning (i form av en functor eller funksjon) er tilgjengelig. E. g.: En kompleks, kan ikke brukes som nøkkel for et kart med mindre en sammenligning er gitt. Dessverre, kompilatorer historisk generere noe esoterisk, lang tid, og lite feilmeldinger for denne typen feil. Å sikre at et bestemt objekt fester seg til en metode protokollen kan lindre dette problemet. Språk som bruker sammenligne i stedet for < kan også bruke komplekse verdier som nøkler.,

Den andre slags mal, en klasse mal, strekker det samme konseptet til klasser. En klasse mal spesialisering er en klasse. Klasse maler er ofte brukt til å lage generiske beholdere. For eksempel, STL har en lenket liste container. For å gjøre en lenket liste av heltall, man skriver liste<int>. En liste av strenger er merket liste<string>. En liste er et sett av standard funksjoner forbundet med det, som fungerer for alle kompatible parameterizing typer.,

Mal specializationEdit

En kraftig funksjon i C++’s maler er malen spesialisering. Dette gjør at alternative implementasjoner til å bli levert basert på visse egenskaper av parameterized type som blir startet. Mal spesialisering har to formål: å tillate visse former for optimalisering, og for å redusere koden bloat.

For eksempel, tenk deg en sorter() mal-funksjonen. En av de primære aktiviteter som en slik funksjon gjør er å bytte eller exchange-verdiene i to av beholderen er posisjoner., Dersom verdiene er store (i form av antall byte som det tar å lagre hvert av dem), så er det ofte raskere å først bygge opp en egen liste med pekere til objekter, sortere dem tips, og deretter bygge den endelige sortert rekkefølge. Dersom verdiene er ganske liten, men det er vanligvis raskeste til å bare bytte verdier på stedet som trengs. Videre, hvis parameterized typen er allerede noen av peker-type, så er det ikke nødvendig å bygge et eget pekeren utvalg., Mal spesialisering gjør at malen creator til å skrive forskjellige implementeringer, og angi egenskapene som parameterized typen(e) må ha for hver gjennomføring skal brukes.

i Motsetning til funksjon maler, klasse maler kan være delvis spesialisert. Det betyr at en alternativ versjon av klassen mal-kode kan bli gitt når noen av malen parametere er kjent, mens man lar andre mal parametere generisk., Dette kan for eksempel brukes til å lage en standard for gjennomføring (den primære spesialisering) som forutsetter at kopiering av en parameterizing type er dyrt, og deretter opprette delvis spesialisering for typer som er billig å kopiere, og dermed øke den generelle effektiviteten. Kunder av en slik klasse mal bare bruke spesialisering av det uten at du trenger å vite om kompilatoren brukt den primære spesialisering eller noen delvis spesialisering i hvert enkelt tilfelle., Klasse maler kan også være fullt spesialisert, noe som betyr at en alternativ implementering kan bli gitt når alle parameterizing typer er kjent.

Fordeler og disadvantagesEdit

Noen bruker maler, for eksempel maks () – funksjonen, tidligere var fylt av funksjon-som preprocessor makroer (en arv av C programmeringsspråk). For eksempel, her er en mulig max() makro:

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

Makroer er utvidet med preprosessor, før samling riktig; – maler er utvidet til kompilere tid., Makroer er alltid utvidet inline; maler kan også utvides så innebygde funksjoner når kompilatoren finner det hensiktsmessig. Dermed både funksjon-som makroer og funksjon maler har ingen run-time overhead.

Imidlertid maler er generelt ansett for å være en forbedring i forhold til makroer for disse formålene. Maler er type-safe. Maler unngå noen av de vanligste feilene som er funnet i koden som gjør mye bruk av funksjonen-som makroer, slik som evaluering av parametre med bivirkninger to ganger. Kanskje viktigst av alt, maler ble designet for å være anvendelig til mye større problemer enn makroer.,

Det er fire primære ulemper med å bruke maler: hvilke funksjoner som støttes, kompilatoren støtte, dårlig feilmeldinger, og koden bloat:

  1. Maler i C++ mangler mange funksjoner, noe som gjør implementere dem og bruke dem på en enkel måte ofte umulig. I stedet programmerere å stole på kompliserte triks som fører til oppblåst, vanskelig å forstå og vanskelig å vedlikeholde kode. Nåværende utviklingen i C++ standarder forverre dette problemet ved å gjøre mye bruk av disse triksene og bygge opp en masse nye funksjoner for maler på dem eller med dem i tankene.,
  2. Mange kompilatorer historisk sett har dårlig støtte for maler, og dermed bruk av maler kan gjøre koden noe mindre bærbare. Støtten kan også være dårlig når en C++ – kompilator brukes med linker som ikke C++-klar, eller når du forsøker å bruke maler over på delt bibliotek grenser. De fleste moderne kompilatorer men nå har ganske robust og standard mal støtte, og den nye C++ standard, C++11, videre tar tak i disse problemene.
  3. Nesten alle kompilatorer produsere forvirrende, lange, eller noen ganger hjelper lite feilmeldinger når feil er oppdaget i koden som bruker maler., Dette kan gjøre maler vanskelig å utvikle.
  4. til Slutt, bruk av maler krever kompilatoren for å generere en separat forekomst av templated klasse eller funksjon for hver permutasjon av type parametre brukt med det. (Dette er nødvendig fordi typer i C++ er ikke alle samme størrelse, og størrelser av data felt er viktige for hvordan klasser arbeid.) Så ukritisk bruk av maler kan føre til koden bloat, noe som resulterer i for stor kjørbare filer., Imidlertid, fornuftig bruk av malen spesialisering og avledning kan dramatisk redusere slik kode bloat i noen tilfeller:

Så, kan derivasjon brukes til å redusere problemet med kode replikert fordi maler brukes? Dette ville innebære å derivere en mal fra en ordinær klasse. Denne teknikken viste seg å være vellykket i nedtoningen kode bloat i reell bruk. Folk som ikke bruker en teknikk som dette har funnet at kopiert koden kan koste megabyte kode plass selv i moderat størrelse programmer.,

— Bjarne Stroustrup, Design og Utvikling av C++, 1994

Den ekstra instantiations generert av maler kan også føre til debuggers å ha problemer med å fungere normalt med maler. For eksempel, sette en debug stoppunkt i en mal fra en kilde filen kan enten gå glipp av innstillingen stoppunkt i selve oppretting ønsket eller kan du angi et stoppunkt i alle plasser malen er instansiert.,

Også, fordi kompilatoren trenger for å utføre makro-som utvidelser av maler og generere ulike forekomster av dem på kompilere tid, gjennomføring kildekoden for templated klasse eller må funksjonen være tilgjengelig (f.eks. inngår i en header) til koden ved hjelp av det. Templated klasser eller funksjoner, inkludert mye av Standard Template Library (STL), hvis ikke er inkludert i header-filer, kan ikke bli samlet. (Dette er i motsetning til ikke-templated koden, som kan kompileres til binære, og gir kun en erklæringer header-filen for koden ved hjelp av det.,) Dette kan være en ulempe ved å utsette implementering av koden, som fjerner noen av abstraksjoner, og kunne begrense sin bruk i lukket kildekode-prosjekter.

Maler i DEdit

D programmeringsspråk som støtter maler basert i design på C++.,De fleste C++ mal idiomer vil bære over til D uten endring, men D legger til noen ekstra funksjoner:

  • Mal parametere i D er ikke begrenset til bare typer og primitive verdier, men også tillate vilkårlige compile-time-verdier (for eksempel strenger og sin struct verdiane), og aliaser til vilkårlig identifikatorer, inkludert andre maler eller mal instantiations.
  • Mal begrensninger og statisk if-setning tilby et alternativ til C++’s substitusjon feil er ikke en feil (SFINAE) mekanisme, som ligner på C++ konsepter.
  • Det er(…,) uttrykk kan spekulative oppretting å bekrefte en objektets egenskaper ved kompilere tid.
  • auto søkeord og typeof uttrykk tillate type slutning for variabel-deklarasjoner og funksjonen returnere verdier, som i sin tur gjør at «Voldemort typer» (typer som ikke har en global navn).

Maler i D bruke en annen syntaks enn i C++: mens i C++ mal parametrene er pakket inn i spisse klammer (Mal<param1, param2>),D bruker et () – tegn og parenteser: Mal!(param1, param2).,Dette unngår C++ parsing vanskeligheter på grunn av tvetydighet med sammenligningen operatører.Hvis det er kun én parameter, er parenteser kan være utelatt.

Konvensjonelt, D kombinerer de ovennevnte funksjoner for å gi compile-time polymorphism ved hjelp av trekk-basert generisk programmering.,For eksempel, en inngangen utvalg er definert som alle type som tilfredsstiller de kontrollene som er utført av isInputRange, som er definert som følger:

En funksjon som aksepterer bare input områder kan deretter bruke de ovennevnte mal en mal begrensning:

auto fun(Range)(Range range) if (isInputRange!Range){ // ...}
– Koden generationEdit

I tillegg til mal metaprogramming, D gir også flere funksjoner for å aktivere compile-time code generation:

  • import uttrykket gjør at du leser en fil fra disk og bruke innholdet som en streng uttrykk.,
  • Utarbeide gang refleksjon gir opplisting og inspeksjon erklæringer og deres medlemmer under kompilering.
  • brukerdefinerte egenskaper tillate brukere å koble vilkårlig identifikatorer til erklæringer, som kan være nummerert med compile-time refleksjon.
  • Compile-Time-Funksjon Gjennomføring (CTFE) gir en delmengde av D (begrenset til sikker drift) skal tolkes under kompilering.
  • String mixins tillate evaluering og sammenstilling av innholdet i et strenguttrykk som D-koden som blir en del av programmet.,

Kombinerer de ovenfor kan generere kode basert på eksisterende bestemmelser.For eksempel, D serialisering rammer kan spesifisere en type medlemmer og generere spesialiserte funksjoner for hver serialisert typeto utføre serialisering og deserialisering.Bruker-definerte attributter kan videre indikere serialisering regler.

import uttrykk og compile-time-funksjon kjøring også tillate effektivt å implementere domene-spesifikke språk.,For eksempel, gitt en funksjon som tar en string som inneholder en HTML-mal og returnerer tilsvarende D kildekode, er det mulig å bruke det på følgende måte:

Genericity i EiffelEdit

Generiske klasser har vært en del av Eiffel siden den opprinnelige metode og språk design. Stiftelsen publikasjoner av Eiffel, bruker begrepet genericity å beskrive etablering og bruk av generiske klasser.

Basic/Fri genericityEdit

Generiske klasser er deklarert med sin klasse navn, og en liste av en eller flere formelle generiske parametre., I det følgende kode, klasse LIST har en formell generisk parameter G

Den formelle generiske parametre er plassholdere for vilkårlig klasse navn som vil bli levert når en erklæring om den generiske klassen er laget, som vist i de to generisk forklaringer nedenfor der ACCOUNT og DEPOSIT er andre klasse navn. ACCOUNT og DEPOSIT anses som faktiske generiske parametere som de gir virkelig klasse navn til erstatning for G i faktisk bruk.,

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

Innenfor Eiffel type system, selv om klassen LIST regnes som en klasse, det er ikke betraktet som en type. Imidlertid er det en generisk avledning av LIST eksempel LIST regnes som en type.

Begrenset genericityEdit

For listen klasse vist ovenfor, er en faktisk generisk parameter erstatter G kan være andre tilgjengelige klasse., For å begrense sett med klasser som gyldig faktiske generiske parametere kan være valgt, en generell begrensning kan være angitt. I erklæringen av klasse SORTED_LIST nedenfor, er den generisk for begrensning tilsier at enhver gyldig faktiske generisk parameter vil være en klasse som arver fra klassen COMPARABLE. Generisk begrensning sørger for at elementene i en SORTED_LIST kan faktisk være sortert.,

class SORTED_LIST 

Generika i JavaEdit

utdypende artikkel: Generics i Java

Støtte for generiske legemidler, eller «containere-of-type-T» ble lagt til i Java programmeringsspråk i 2004 som en del av J2SE 5.0. I Java, generika er bare sjekket på kompilere tid for type korrekthet. Den generiske typen informasjon er fjernet via en prosess som kalles type sletting, for å opprettholde kompatibilitet med gamle JVM-implementeringer, noe som gjør det utilgjengelig ved kjøring., For eksempel, en Liste<String> er konverterte til raw-type-Listen. Kompilatoren innlegg skriver du kaster for å konvertere elementer til String type når de hentes fra listen, redusere ytelsen i forhold til andre implementasjoner, for eksempel C++ maler.

Genericity i .NETTO Rediger

Generics ble lagt inn som en del av .NET Framework 2.0 i November 2005, basert på forskning prototype fra Microsoft Research startet i 1999. Selv om lignende generika i Java, .,NETTO generiske ikke gjelder type sletting, men implementere generika som en første klasse mekanisme i runtime ved hjelp av reification. Dette design-valg gir ekstra funksjonalitet, som gir refleksjon med bevaring av generiske typer, samt å lette noen av begrensningene for sletting (for eksempel å være i stand til å skape generisk matriser). Dette betyr også at det er ingen ytelse hit fra runtime kaster, og det er normalt dyrere boksing konverteringer., Når primitive og verdi-typer er brukt som generisk argumenter, får de spesialiserte implementeringer, slik at for effektiv generisk samlinger og metoder. Som i C++ og Java, nestede generiske typer, for eksempel Ordlisten<string, Liste<int>> er gyldig typer, men er det advares mot for medlem signaturer i koden analyse design regler.

.,NET tillater seks varianter av generisk type begrensninger ved å bruke der søkeordet inkludert begrense generiske typer å være verdi-typer, for å være klasser, for å ha konstruktører, og å implementere grensesnitt. Nedenfor er et eksempel med et grensesnitt begrensning:

MakeAtLeast () – metoden tillater drift på matriser, med elementer av generisk type T. metoden type begrensning indikerer at metoden er anvendelig til alle type T som implementerer den generisk IComparable<T> grensesnitt., Dette sikrer en kompilere tid feil, hvis metoden kalles opp hvis typen din støtter ikke sammenligningen. Grensesnittet gir den generisk metoden CompareTo(T).

Den ovennevnte metoden kan også være skrevet uten generiske typer, bare å bruke ikke-generisk Matrise. Imidlertid, siden matriser er contravariant, støping ville ikke være typen som er trygg, og kompilatoren ikke ville være i stand til å finne visse mulige feil som ellers ville bli fanget når du bruker generiske typer. I tillegg er metoden skulle trenge å få tilgang til array-elementer som objekter i stedet, og ville kreve støping å sammenligne to elementer., (For verdi-typer som typer, for eksempel int dette krever en boksing konvertering, selv om dette kan være jobbet rundt ved hjelp av den Comparer<T> – klassen, som er gjort i standard samling klasser.)

En tvilsom oppførsel av statiske medlemmer i en generisk .NET klasse er statisk medlem oppretting per run-time-type (se eksempel nedenfor).

Genericity i DelphiEdit

Delphi ‘ s Object Pascal dialekt kjøpt generika i Delphi 2007 utgivelsen, i første omgang kun med (nå nedlagt) .,NET-kompilator før de blir lagt til den opprinnelige koden i Delphi 2009 utgivelsen. Semantikk og evner i Delphi generiske legemidler er i stor grad basert på de hadde av generiske legemidler i .NET 2.0, selv om implementeringen av nødvendighet ganske annerledes. Her er en mer eller mindre direkte oversettelse av den første C# eksempel vist ovenfor:

Som med C#, metoder så vel som hele typer kan ha én eller flere type parametere. I eksempelet, TArray er en generisk type (definert av språk) og MakeAtLeast en generisk metode., De tilgjengelige begrensninger er svært lik den tilgjengelige begrensninger i C#: en hvilken som helst verdi type, noen klasse, en bestemt klasse eller grensesnitt, og en klasse med en parameterless constructor. Flere begrensninger fungere som en additiv union.

Genericity i Gratis PascalEdit

Gratis Pascal implementert generiske før Delphi, og med ulik syntaks og semantikk. Imidlertid, siden FPC versjon 2.6.0, Delphi-stil syntaks er tilgjengelig når du bruker {$modus Delphi} språk-modus. Dermed Free Pascal programmerere er i stand til å bruke generics i hvilken stil de foretrekker.,

Delphi og Free Pascal eksempel:

Funksjonell languagesEdit

Genericity i HaskellEdit

Den type klasse mekanisme av Haskell støtter generisk programmering.Seks av de forhåndsdefinerte type klasser i Haskell (inkludert Eq, de typer som kan sammenlignes med for likestilling, og for å Vise, hvilke typer verdier som kan gjengis som strenger) har den spesielle egenskapen av å støtte avledet tilfeller., Dette betyr at en programmerer som definerer en ny type kan si at denne typen er å være en forekomst av en av disse spesielle type klasser, uten å gi implementeringer av klasse metoder som er vanligvis nødvendig når erklære klasse tilfeller. Alle nødvendige metoder vil bli «avledet» – som er laget automatisk – basert på strukturen av den typen.,For eksempel, følgende erklæring av en type av binære trær sier at det er å være en forekomst av klasser Eq og Show:

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

Dette resulterer i et likestillings-funksjon (==) og en streng representasjon funksjon (vis) blir automatisk definert for alle type form BinTree T forutsatt at T selv støtter disse operasjonene.,

støtte for avledet forekomster av Eq og Vis gjør sine metoder == og vis generisk i en kvalitativt annen måte fra para-metrically polymorf funksjoner: disse «funksjoner» (mer nøyaktig, type-indeksert familier av funksjoner) kan brukes til verdier av ulike typer, og selv om de oppfører seg annerledes for ethvert argument type, lite arbeid er nødvendig for å legge til støtte for en ny type. Ralf Hinze (2004) har vist at en lignende effekt kan oppnås for brukerdefinert type klasser av visse programmering teknikker., Andre forskere har foreslått tilnærminger til denne og andre typer genericity i sammenheng med Haskell og utvidelser til Haskell (diskutert nedenfor).

PolyPEdit

Polypper var den første generisk programmering språk extension til Haskell. I Polypper, generisk funksjoner kalles polytypic. Språket introduserer en spesiell konstruksjon som slike polytypic funksjoner kan defineres via strukturell induksjon over oppbyggingen av mønster functor av en vanlig datatype. Vanlige datatyper i Polypper er et delsett av Haskell datatyper., En vanlig datatype t må være av typen * → *, og hvis en er den formelle typen argument i definisjonen, så alle rekursiv anrop til t må ha form t en. Disse restriksjonene utelukke høyere kinded datatyper, samt nestede datatyper, hvor rekursiv samtaler, er av en annen form.Den flate funksjon i Polypper er her gitt som et eksempel:

Generisk HaskellEdit

Generisk Haskell er en utvidelse til Haskell, utviklet ved Utrecht Universitet i Nederland., Utvidelser som det gir er:

  • Skriv-indekserte verdier er definert som en verdi indeksert over de ulike Haskell type konstruktører (enhet, primitive typer, summer, produkter, og brukerdefinert type konstruktører). I tillegg kan vi også angi oppførsel av en type-indekserte verdier for en bestemt konstruktør ved hjelp av konstruktøren tilfeller, og gjenbruke en generell definisjon i en annen ved hjelp av standard tilfeller.

Den resulterende type-indeksert verdi kan være spesialisert i noen form.

  • Like-indeksert typer typer indeksert over slag, definert ved å gi en sak for både * og k → k’., Forekomstene er innhentet ved bruk av slag-indeksert type til type.
  • Generisk definisjoner kan brukes ved å bruke dem til en type eller form. Dette kalles generisk programmet. Resultatet er en type eller en verdi, avhengig av hvilken form for generell definisjon er brukt.
  • Generisk uttak gjør generisk definisjoner vil bli definert av abstracting en parameter (av en gitt type).
  • Skriv inn indeksert typer er typer som er indeksert over den type konstruktører. Disse kan brukes til å gi typer til mer involvert generelle verdier., Den resulterende type-indeksert typer kan være spesialisert i noen form.

Som et eksempel, likestillings-funksjonen i Generisk Haskell:

CleanEdit

Rengjør og tilbyr generisk programmering basert Polypper og den generisk Haskell som støttes av GHC>=6.0. Det parametrizes av typen som dem, men tilbyr overbelastning.

Andre languagesEdit

ML familie av programmeringsspråk støtte generisk programmering gjennom parametrisk polymorphism og generiske moduler kalles functors.,Både Standard ML og OCaml gi functors, som er tilsvarende klasse maler og Ada ‘ s generiske pakker. Ordningen syntaktiske abstraksjoner har også en forbindelse til genericity – dette er faktisk et overordnet sett for templating à la C++.

En Verilog-modul kan ta ett eller flere parametre, som deres faktiske verdier er tildelt ved oppretting av modulen. Ett eksempel er en generisk registrere matrise der matrisen bredde er gitt via en parameter., Slik tabellen, kombinert med en generell wire vektor, kan gjøre en generell buffer eller minnemodul med en tilfeldig bit bredde ut av en enkelt modul gjennomføring.

VHDL, blir avledet fra Ada, har også generisk evner.