szablony w edycji C++
C++ używa szablonów, aby włączyć ogólne techniki programowania. C++ Standard Library zawiera standardową bibliotekę szablonów lub STL, która zapewnia ramy szablonów dla wspólnych struktur danych i algorytmów. Szablony w C++ mogą być również używane do metaprogramowania szablonów, co jest sposobem wstępnej oceny części kodu w czasie kompilacji, a nie w czasie wykonywania. Korzystając ze specjalizacji szablonów, Szablony C++ są uważane za kompletne.,
przegląd Technicznydit
istnieją dwa rodzaje szablonów: szablony funkcji i szablony klas. Szablon funkcji jest wzorcem do tworzenia zwykłych funkcji w oparciu o typy parametryzujące dostarczane podczas tworzenia instancji. Na przykład standardowa biblioteka szablonów C++ zawiera szablon funkcji max (X, y), który tworzy funkcje zwracające x lub y, w zależności od tego, która z tych wartości jest większa., max()
można zdefiniować w następujący sposób:
template <typename T>T max(T x, T y) { return x < y ? y : x;}
specjalizacje tego szablonu funkcji, instancje o określonych typach, mogą być wywoływane tak jak zwykła funkcja:
std::cout << max(3, 7); // Outputs 7.
kompilator analizuje argumenty użyte do wywołania Max i określa, że jest to wywołanie Max(int, int)., Następnie tworzy instancję wersji funkcji, w której parametryzującym typem T jest int, co czyni ją odpowiednikiem następującej funkcji:
int max(int x, int y) { return x < y ? y : x;}
działa to niezależnie od tego, czy argumenty x i y są liczbami całkowitymi, łańcuchami lub dowolnym innym typem, dla którego wyrażenie x < y jest sensowne, a dokładniej dla dowolnego typu Dla który operator< jest zdefiniowany. Wspólne dziedziczenie nie jest potrzebne dla zestawu typów, które mogą być używane, a więc jest bardzo podobne do typowania kaczek., Program definiujący niestandardowy typ danych może użyć overloading operatora do zdefiniowania znaczenia < dla tego typu, umożliwiając w ten sposób jego użycie z szablonem funkcji max (). Chociaż może się to wydawać niewielką korzyścią w tym odosobnionym przykładzie, w kontekście obszernej biblioteki, takiej jak STL, pozwala programistom uzyskać rozbudowaną funkcjonalność dla nowego typu danych, po prostu przez zdefiniowanie kilku operatorów dla niego., Samo zdefiniowanie< pozwala na użycie typu ze standardowymi algorytmami sort(), stable_sort () i binary_search() lub umieszczenie go wewnątrz struktur danych, takich jak zestawy, stosy i tablice asocjacyjne.
szablony C++ są całkowicie bezpieczne w czasie kompilacji. Jako przykład, standardowy typ complex nie definiuje operatora<, ponieważ nie ma ścisłego porządku na liczbach zespolonych. Dlatego max (X, y) zakończy się błędem kompilacji, jeśli x i y są wartościami złożonymi., Podobnie inne szablony bazujące na < nie mogą być stosowane do złożonych danych, chyba że zostanie zapewnione porównanie (w formie funktora lub funkcji). Na przykład: kompleks nie może być używany jako klucz dla mapy, chyba że zostanie dostarczone porównanie. Niestety, Kompilatory historycznie generują Ezoteryczne, długie i nieprzydatne komunikaty o błędach dla tego rodzaju błędów. Upewnienie się, że dany obiekt przylega do protokołu metody może rozwiązać ten problem. Języki, które używają compare zamiast < mogą również używać złożonych wartości jako kluczy.,
drugi rodzaj szablonu, szablon klasy, rozszerza tę samą koncepcję na klasy. Specjalizacja szablonu klasy to klasa. Szablony klas są często używane do tworzenia ogólnych kontenerów. Na przykład, STL ma kontener listy połączonej. Aby utworzyć połączoną listę liczb całkowitych, należy zapisać listę <int>. Lista łańcuchów jest oznaczona listą <łańcuch>. Lista zawiera zestaw standardowych funkcji powiązanych z nią, które działają dla wszystkich kompatybilnych typów parametryzujących.,
Template specializationEdit
potężną cechą szablonów C++jest specjalizacja szablonów. Pozwala to na dostarczenie alternatywnych implementacji w oparciu o pewne cechy parametryzowanego typu, który jest inicjowany. Specjalizacja szablonów ma dwa cele: umożliwienie pewnych form optymalizacji oraz ograniczenie nadmiarowości kodu.
na przykład rozważmy funkcję szablonu sort (). Jedną z podstawowych czynności wykonywanych przez taką funkcję jest zamiana lub wymiana wartości w dwóch pozycjach kontenera., Jeżeli wartości są duże (pod względem ilości bajtów potrzebnych do przechowywania każdego z nich), wtedy często szybciej jest najpierw zbudować oddzielną listę wskaźników do obiektów, posortować te wskaźniki, a następnie zbudować finalną posortowaną sekwencję. Jeśli wartości są dość małe, zwykle jest to najszybsze, aby po prostu zamienić wartości na miejscu w razie potrzeby. Ponadto, jeżeli parametryzowany typ jest już typu wskaźnikowego, wtedy nie ma potrzeby budowania oddzielnej tablicy wskaźników., Specjalizacja szablonów pozwala twórcom szablonów pisać różne implementacje i określać cechy, które parametryzowane typy muszą mieć dla każdej implementacji, która ma być użyta.
w przeciwieństwie do szablonów funkcji, szablony klas mogą być częściowo wyspecjalizowane. Oznacza to, że alternatywna wersja kodu szablonu klasy może być dostarczona, gdy niektóre parametry szablonu są znane, pozostawiając inne parametry szablonu ogólne., Można to wykorzystać na przykład do stworzenia domyślnej implementacji (podstawowej specjalizacji), która zakłada, że kopiowanie parametryzującego typu jest drogie, a następnie tworzy częściowe Specjalizacje dla typów, które są tanie w kopiowaniu, zwiększając w ten sposób ogólną wydajność. Klienci takiego szablonu klasy po prostu używają jego specjalizacji bez potrzeby wiedzieć, czy kompilator używał podstawowej specjalizacji czy jakiejś częściowej specjalizacji w każdym przypadku., Szablony klas mogą być również w pełni wyspecjalizowane, co oznacza, że alternatywna implementacja może być dostarczona, gdy znane są wszystkie typy parametryzujące.
zalety i wadeedit
niektóre zastosowania szablonów, takie jak funkcja max (), były wcześniej wypełnione przez funkcje-podobne makra preprocesora (dziedzictwo języka programowania C). Na przykład, tutaj jest możliwe makro max ():
#define max(a,b) ((a) < (b) ? (b) : (a))
makra są rozszerzane przez preprocesor, przed właściwą kompilacją; szablony są rozszerzane podczas kompilacji., Makra są zawsze rozwijane inline; szablony mogą być również rozwijane jako funkcje inline, gdy kompilator uzna to za stosowne. Tak więc zarówno makra podobne do funkcji, jak i szablony funkcji nie mają narzutu czasu pracy.
jednak szablony są ogólnie uważane za ulepszenie w stosunku do makr do tych celów. Szablony są bezpieczne dla typu. Szablony unikają niektórych typowych błędów występujących w kodzie, który w dużym stopniu wykorzystuje makra podobne do funkcji, takie jak Dwukrotna ocena parametrów z efektami ubocznymi. Być może najważniejsze, szablony zostały zaprojektowane tak, aby mogły być stosowane do znacznie większych problemów niż makra.,
istnieją cztery główne wady korzystania z szablonów: obsługiwane Funkcje, Obsługa kompilatorów, słabe komunikaty o błędach i nadęty Kod:
- szablony w C++ nie mają wielu funkcji, co sprawia, że ich implementacja i używanie w prosty sposób często jest niemożliwe. Zamiast tego programiści muszą polegać na skomplikowanych sztuczkach, które prowadzą do nadętego, trudnego do zrozumienia i trudnego do utrzymania kodu. Obecne zmiany w standardach C++ pogłębiają ten problem poprzez intensywne wykorzystanie tych sztuczek i budowanie wielu nowych funkcji dla szablonów na nich lub z ich myślą.,
- wiele kompilatorów historycznie ma słabe wsparcie dla szablonów, dlatego użycie szablonów może uczynić kod nieco mniej przenośnym. Wsparcie może być również słabe, gdy kompilator C++ jest używany z linkerem, który nie jest świadomy C++, lub gdy próbuje użyć szablonów ponad granicami współdzielonych bibliotek. Większość współczesnych kompilatorów ma jednak teraz dość solidną i standardową obsługę szablonów, a nowy standard C++, C++11, rozwiązuje te problemy.
- prawie wszystkie Kompilatory wytwarzają mylące, długie lub czasami nieprzydatne komunikaty o błędach, gdy błędy są wykrywane w kodzie używającym szablonów., Może to utrudnić tworzenie szablonów.
- wreszcie, użycie szablonów wymaga, aby kompilator generował osobną instancję klasy szablonowej lub funkcji dla każdej permutacji parametrów typu używanych z nią. (Jest to konieczne, ponieważ typy w C++ nie wszystkie mają ten sam rozmiar, a rozmiary pól danych są ważne dla działania klas.), Więc masowe użycie szablonów może prowadzić do nadmiarowości kodu, co skutkuje nadmiernie dużymi plikami wykonywalnymi., Jednak rozsądne użycie specjalizacji i derywacji szablonów może w niektórych przypadkach znacznie zmniejszyć takie nadmuchanie kodu:
czy zatem derywacja może być stosowana w celu zmniejszenia problemu powielania kodu, ponieważ używane są szablony? Wiązałoby się to z wyprowadzeniem szablonu ze zwykłej klasy. Technika ta okazała się skuteczna w ograniczaniu nadęcia kodu w rzeczywistym użyciu. Ludzie, którzy nie używają takiej techniki, odkryli, że replikowany kod może kosztować megabajty przestrzeni kodowej nawet w programach o umiarkowanej wielkości.,
— Bjarne Stroustrup, the Design and Evolution of C++, 1994
dodatkowe instancje generowane przez szablony mogą również powodować trudności w pracy z szablonami. Na przykład ustawienie punktu przerwania debugowania w szablonie z pliku źródłowego może albo pominąć Ustawienie punktu przerwania w żądanej rzeczywistej instancji lub może ustawić punkt przerwania w każdym miejscu, w którym szablon jest tworzony.,
Ponadto, ponieważ kompilator musi wykonywać makro-podobne rozszerzenia szablonów i generować różne ich instancje w czasie kompilacji, kod źródłowy implementacji dla klasy szablonów lub funkcji musi być dostępny (np. zawarty w nagłówku) dla kodu, który go używa. Klasy lub funkcje template, w tym większość standardowej biblioteki szablonów (STL), jeśli nie są zawarte w plikach nagłówkowych, nie mogą być skompilowane. (Jest to w przeciwieństwie do kodu nie-szablonowego, który może być skompilowany do binarnego, dostarczając tylko plik nagłówkowy deklaracji dla kodu używającego go.,) Może to być wadą poprzez ujawnienie kodu implementującego, który usuwa pewne abstrakcje i może ograniczyć jego użycie w projektach o zamkniętym źródle.
szablony w DEdit
język programowania D obsługuje szablony oparte na C++.,Większość idiomów szablonów C++ przenosi się do D bez zmian, ale D dodaje kilka dodatkowych funkcji:
- parametry szablonów w D nie są ograniczone tylko do typów i prymitywnych wartości, ale także pozwalają na dowolne wartości w czasie kompilacji (takie jak ciągi znaków i literały struct) i aliasy do dowolnych identyfikatorów, w tym innych szablonów lub instancji szablonów.
- ograniczenia szablonów i statyczna Instrukcja if stanowią alternatywę dla mechanizmu substitution failure C++nie jest mechanizmem błędu (SFINAE), podobnym do koncepcji C++.
- jest(…,) wyrażenie pozwala spekulatywnej instancji zweryfikować cechy obiektu w czasie kompilacji.
- słowo kluczowe auto i wyrażenie typeof umożliwiają wnioskowanie typu dla deklaracji zmiennych i wartości zwracanych funkcji, co z kolei pozwala na „typy Voldemorta” (typy, które nie mają globalnej nazwy).
szablony w D używają innej składni niż w C++: podczas gdy w C++ parametry szablonu są zawinięte w nawiasy kątowe (Template<param1, param2>),D używa znaku wykrzyknika i nawiasów: Template!(param1, param2).,Pozwala to uniknąć trudności w parsowaniu C++ z powodu niejednoznaczności z operatorami porównania.Jeśli jest tylko jeden parametr, nawiasy można pominąć.
konwencjonalnie D łączy powyższe funkcje, aby zapewnić polimorfizm w czasie kompilacji za pomocą ogólnego programowania opartego na cechach.,Na przykład, zakres wejściowy jest zdefiniowany jako dowolny typ, który spełnia kontrole wykonywane przez isInputRange, który jest zdefiniowany w następujący sposób:
funkcja, która akceptuje tylko zakresy wejściowe, może następnie użyć powyższego szablonu w ograniczeniu szablonu:
auto fun(Range)(Range range) if (isInputRange!Range){ // ...}
generowanie Koduedit
oprócz metaprogramowania szablonu, D zapewnia również kilka funkcji umożliwiających kompilację-generowanie kodu czasowego:
- wyrażenie import umożliwia odczyt pliku z dysku i wykorzystanie jego zawartości jako wyrażenia łańcuchowego.,
- Compile-time reflection umożliwia Wyliczanie i sprawdzanie deklaracji i ich członków podczas kompilacji.
- atrybuty zdefiniowane przez użytkownika umożliwiają dołączanie dowolnych identyfikatorów do deklaracji, które mogą być następnie wyliczane za pomocą refleksji w czasie kompilacji.
- Compile-Time Function Execution (CTFE) pozwala na interpretację podzbioru D (ograniczonego do bezpiecznych operacji) podczas kompilacji.
- string mixins umożliwia ocenę i kompilację zawartości wyrażenia łańcuchowego jako kodu D, który staje się częścią programu.,
połączenie powyższego kodu umożliwia generowanie kodu w oparciu o istniejące deklaracje.Na przykład frameworki serializacji D mogą wyliczać składowe danego typu i generować wyspecjalizowane funkcje dla każdego typu serializowanego do wykonywania serializacji i deserializacji.Zdefiniowane przez użytkownika atrybuty mogą dodatkowo wskazywać reguły serializacji.
zaimportowanie wyrażenia i wykonanie funkcji w czasie kompilacji umożliwiają również efektywne implementowanie języków specyficznych dla domeny.,Na przykład, biorąc pod uwagę funkcję, która pobiera łańcuch zawierający szablon HTML i zwraca równoważny kod źródłowy D, można go użyć w następujący sposób:
Genericity in EiffelEdit
klasy generyczne są częścią Eiffel od czasu oryginalnej metody i projektu języka. Publikacje Fundacji Eiffla używają terminu generyczność do opisania tworzenia i używania klas generycznych.
basic/Unstrained genericityEdit
klasy generyczne są deklarowane z ich nazwą i listą jednego lub więcej formalnych parametrów generycznych., W poniższym kodzie Klasa LIST
ma jeden formalny parametr generyczny G
formalne parametry generyczne są zastępcami dla dowolnych nazw klas, które zostaną dostarczone podczas składania deklaracji klasy generycznej, jak pokazano w dwóch generycznych pochodniach poniżej, gdzie ACCOUNT
I DEPOSIT
to Inne nazwy klas. ACCOUNT
I DEPOSIT
są uważane za rzeczywiste parametry ogólne, ponieważ zapewniają prawdziwe nazwy klas, które można zastąpić G
w rzeczywistym użyciu.,
list_of_accounts: LIST -- Account list list_of_deposits: LIST -- Deposit list
w systemie typu Eiffel, chociaż KlasaLIST
jest uważana za klasę, nie jest uważana za Typ. Jednak generyczna pochodna LIST
taka jak LIST
jest uważana za Typ.
ograniczona genericityEdit
dla klasy listy pokazanej powyżej, rzeczywisty parametr generyczny zastępującyG
może być dowolną inną dostępną klasą., Aby ograniczyć zestaw klas, z których można wybrać prawidłowe rzeczywiste parametry ogólne, można określić ogólne Ograniczenie. W deklaracji klasy SORTED_LIST
poniżej, ogólne Ograniczenie nakazuje, że każdy prawidłowy rzeczywisty parametr generyczny będzie klasą, która dziedziczy z klasy COMPARABLE
. Ograniczenie ogólne zapewnia, że elementy SORTED_LIST
mogą być faktycznie sortowane.,
class SORTED_LIST
Generics in JavaEdit
Wsparcie dla generics, lub „containers-of-type-T” został dodany do języka programowania Java w 2004 roku jako część J2SE 5.0. W Javie generyki są sprawdzane tylko w czasie kompilacji pod kątem poprawności typu. Ogólne informacje o typie są następnie usuwane za pomocą procesu o nazwie type erasure, aby zachować kompatybilność ze starymi implementacjami JVM, co czyni je niedostępnymi w czasie wykonywania., Na przykład lista<ciąg znaków> jest konwertowana do listy typów surowych. Kompilator wstawia Typ, aby przekonwertować elementy na typ String, gdy zostaną pobrane z listy, zmniejszając wydajność w porównaniu do innych implementacji, takich jak szablony C++.
Genericity in.NET Edit
Generics zostały dodane jako część. NET Framework 2.0 w listopadzie 2005 roku, na podstawie prototypu badawczego firmy Microsoft Research rozpoczętego w 1999 roku. Chociaż podobne do generyków w Javie, .,NET generics nie stosuje usuwania typów, ale implementuje generics jako mechanizm pierwszej klasy w uruchomieniu za pomocą reification. Ten wybór projektu zapewnia dodatkowe funkcje, takie jak umożliwienie refleksji z zachowaniem typów generycznych, a także złagodzenie niektórych ograniczeń usuwania (takich jak niemożność tworzenia tablic generycznych). Oznacza to również, że nie ma hitu wydajności z odlewów runtime i zwykle kosztownych konwersji bokserskich., Gdy typy primitive I value są używane jako argumenty generyczne, otrzymują wyspecjalizowane implementacje, pozwalające na wydajne zbiory i metody generyczne. Podobnie jak w C++ i Javie, zagnieżdżone typy generyczne, takie jak Dictionary<string, List<int>> są poprawnymi typami, jednak są odradzane dla podpisów członkowskich w regułach projektowania analizy kodu.
.,NET pozwala na sześć odmian ograniczeń typów ogólnych przy użyciu słowa kluczowego where, w tym ograniczenie typów generycznych do typów wartości, do klas, do konstruktorów i do implementacji interfejsów. Poniżej znajduje się przykład z ograniczeniem interfejsu:
metoda MakeAtLeast() umożliwia działanie na tablicach z elementami typu ogólnego T. ograniczenie typu metody wskazuje, że metoda ma zastosowanie do dowolnego typu T, który implementuje ogólny interfejs IComparable<T>., Zapewnia to błąd czasu kompilacji, jeśli metoda jest wywołana, jeśli Typ nie obsługuje porównania. Interfejs zapewnia ogólną metodę CompareTo (T).
powyższa metoda może być również napisana bez typów generycznych, po prostu używając Nie-generycznego typu Array. Jednakże, ponieważ tablice są sprzeczne, odlewanie nie byłoby bezpieczne dla typu, A kompilator nie byłby w stanie znaleźć pewnych możliwych błędów, które w przeciwnym razie zostałyby wychwycone podczas używania typów generycznych. Ponadto metoda musiałaby uzyskać dostęp do elementów tablicy jako obiektów i wymagałaby odlewania, aby porównać dwa elementy., (W przypadku typów wartości, takich jak int, wymaga to konwersji boksu, chociaż można to obejść za pomocą klasy porównawczej<T>, jak to ma miejsce w standardowych klasach kolekcji.)
godnym uwagi zachowaniem statycznych członków w generycznej klasie. NET jest instancja statycznych członków na typ czasu wykonywania (zobacz przykład poniżej).
Generyczność w DelphiEdit
dialekt Object Pascal Delphi nabył generyki w wydaniu Delphi 2007, początkowo tylko z (obecnie wycofanym) .,Kompilator sieci przed dodaniem do kodu natywnego w wydaniu Delphi 2009. Semantyka i możliwości Delphi generics są w dużej mierze wzorowane na tych, które miały generics w. NET 2.0, choć implementacja jest z konieczności zupełnie inna. Oto mniej lub bardziej bezpośrednie tłumaczenie pierwszego przykładu C# pokazanego powyżej:
podobnie jak w C#, metody, jak i całe typy mogą mieć jeden lub więcej parametrów typu. W przykładzie, TArray jest typem generycznym (zdefiniowanym przez język) i MakeAtLeast metodą generyczną., Dostępne ograniczenia są bardzo podobne do ograniczeń dostępnych w C#: dowolny typ wartości, Dowolna Klasa, konkretna klasa lub interfejs oraz klasa z konstruktorem bez parametru. Wiele ograniczeń działa jako związek addytywny.
Generyczność w wolnym PascalEdit
Free Pascal zaimplementował generykę przed Delphi, z inną składnią i semantyką. Jednak od wersji FPC 2.6.0, składnia w stylu Delphi jest dostępna przy użyciu trybu języka {$mode Delphi}. W ten sposób Programiści Free Pascala mogą używać generyków w dowolnym stylu, który preferują.,
Delphi i Free Pascal przykład:
języki Funkcyjneedit
Genericity in HaskellEdit
mechanizm klasy typów Haskell obsługuje programowanie generyczne.Sześć predefiniowanych klas typów w Haskell (w tym Eq, typy, które mogą być porównywane dla równości, i Show, typy, których wartości mogą być renderowane jako ciągi znaków) mają specjalną właściwość obsługi pochodnych instancji., Oznacza to, że programista definiujący nowy typ może stwierdzić, że ten typ ma być instancją jednej z tych specjalnych klas typów, bez dostarczania implementacji metod klasy, co jest zwykle konieczne przy deklarowaniu instancji klasy. Wszystkie niezbędne metody zostaną „wyprowadzone” – czyli skonstruowane automatycznie – w oparciu o strukturę typu.,Na przykład, następująca deklaracja typu drzewa binarnego stwierdza, że ma to być instancja klasy Eq I Show:
data BinTree a = Leaf a | Node (BinTree a) a (BinTree a) deriving (Eq, Show)
powoduje to, że funkcja równości (==) i funkcja reprezentacji łańcuchów (show) są automatycznie definiowane dla dowolnego typu postaci BinTree T pod warunkiem, że sama T obsługuje te operacje.,
Wsparcie dla pochodnych instancji Eq I Show sprawia, że ich metody = = i show generyczne różnią się jakościowo od funkcji para-metrycznie polimorficznych: te „funkcje” (dokładniej, indeksowane przez typ rodziny funkcji) mogą być stosowane do wartości różnych typów i chociaż zachowują się inaczej dla każdego typu argumentu, niewiele pracy jest potrzebne, aby dodać obsługę nowego typu. Ralf Hinze (2004) wykazał, że podobny efekt można osiągnąć dla klas typów zdefiniowanych przez Użytkownika za pomocą pewnych technik programowania., Inni badacze zaproponowali podejścia do tego i innych rodzajów generyczności w kontekście Haskell i rozszerzeń Haskell (omówione poniżej).
PolyPEdit
Polypedit był pierwszym generycznym rozszerzeniem języka programowania Haskell. W polipach funkcje ogólne nazywane są politypicznymi. Język wprowadza specjalny konstrukt, w którym takie funkcje politypiczne mogą być zdefiniowane poprzez indukcję strukturalną nad strukturą funktora wzorcowego regularnego typu danych. Regularne typy danych w polip są podzbiorem typów danych Haskell., Regularny typ danych t musi być typu*→*, A Jeśli a jest argumentem formalnym w definicji, to wszystkie rekurencyjne wywołania do t muszą mieć postać t a. ograniczenia te wykluczają zarówno typy danych o wyższej linii, jak i zagnieżdżone typy danych, gdzie rekurencyjne wywołania mają inną formę.Funkcja spłaszczania w polipie jest tutaj przedstawiona jako przykład:
Generic HaskellEdit
Generic Haskell jest kolejnym rozszerzeniem Haskell, opracowanym na Uniwersytecie w Utrechcie w Holandii., Rozszerzenia, które dostarcza to:
- wartości indeksowane typu są definiowane jako wartości indeksowane przez różne konstruktory typu Haskell (unit, primitive types, sums, products I user-defined type constructors). Ponadto, możemy również określić zachowanie wartości indeksowanych przez typ dla określonego konstruktora za pomocą przypadków konstruktora i ponownie użyć jednej definicji generycznej w innej za pomocą przypadków domyślnych.
wynikowa wartość zindeksowana typu może być dostosowana do dowolnego typu.
- typy indeksowane są typami indeksowanymi nad rodzajami, zdefiniowanymi przez podanie przypadku zarówno dla*, jak i k → k'., Instancje są uzyskiwane przez zastosowanie rodzaju indeksowanego do rodzaju.
- ogólne definicje mogą być używane przez zastosowanie ich do typu lub rodzaju. To się nazywa aplikacja generyczna. Rezultatem jest typ lub wartość, w zależności od rodzaju definicji ogólnej.
- abstrakcja generyczna umożliwia definiowanie definicji generycznych poprzez abstrakcję parametru typu (danego rodzaju).
- typy indeksowane typu są typami indeksowanymi przez konstruktory typu. Mogą one być używane do nadawania typów bardziej zaangażowanym wartościom ogólnym., Wynikowe typy indeksowane typu mogą być wyspecjalizowane do dowolnego typu.
jako przykład, funkcja równości w generycznym Haskell:
CleanEdit
Clean oferuje generyczny polip oparty na programowaniu i generyczny Haskell obsługiwany przez GHC>=6.0. Parametryzuje według rodzaju, ale oferuje przeciążenie.
Inne językiedytuj
rodzina języków programowania ML wspiera programowanie generyczne poprzez parametryczny polimorfizm i generyczne Moduły zwane funktorami.,Zarówno standardowe ML, jak i OCaml dostarczają funktory, które są podobne do szablonów klas I do pakietów generycznych Ada. Abstrakcje składniowe Scheme mają również związek z ogólnością-są to w rzeczywistości superset szablonów a la c++.
moduł Verilog może przyjmować jeden lub więcej parametrów, do których przypisywane są ich rzeczywiste wartości podczas tworzenia modułu. Jednym z przykładów jest ogólna tablica rejestru, gdzie szerokość tablicy jest podawana za pomocą parametru., Taka tablica, w połączeniu z ogólnym wektorem przewodowym, może tworzyć ogólny bufor lub moduł pamięci o dowolnej szerokości bitowej z pojedynczej implementacji modułu.
VHDL, wywodzący się z Ada, ma również ogólne możliwości.
Dodaj komentarz