Co lidé dělali před šablonami v C ++? [duplicate]

Tato otázka již má odpovědi zde :

Komentáře

  • toto bylo pravděpodobně provedeno stejným způsobem jako v obyčejném C, viz Psaní generického kódu, když je vaším cílem kompilátor C
  • Šablony @Telastyn, IIRC, byly novinkou CFront 3 (kolem roku 1990).
  • @Telastyn: kolem roku 2000 většina stávajících překladačů v C ++ neposkytovala šablony příliš dobře (i když předstírali, že je poskytují, většina z nich byla příliš chybná pro použití v produkci). Podpora šablon byla většinou pro podporu obecných kontejnerů, ale zdaleka není potřeba podporovat něco jako Alexandrescu ' s " Moderní design v C ++ " příklady.
  • Jste si jisti, že generování kódu v kompilaci bylo použito před realizací šablon? Byl jsem tehdy mladý, ale mám dojem, že za starých časů byly použity pouze nejjednodušší druhy generování kódu v kompilaci. Pokud jste opravdu chtěli napsat program, který by psal váš program, napsali jste program / skript, jehož výstupem byl zdrojový kód C, místo toho pomocí jazyka šablony.
  • @Joshua – otázky jsou uzavřeny jako duplikáty, pokud stávající odpovědi na jinou otázku řeší primární dotazy za touto otázkou. " Přesné " shody nejsou povinné; jde o to rychle spojit OP s odpověďmi na jejich otázku. Jinými slovy ano, je to ' duplikát. To znamená, že tato otázka zavání " OMG! Jak svět existoval dříve …?! " což není ' strašně konstruktivní otázka. Doc Brown v dřívějším (a nyní smazaném komentáři) poukázal na to, jak může tento fenomén ovlivnit komentář.

Odpověď

Kromě void * ukazatele, který je zahrnut v Robertově odpovědi , byla použita taková technika (odmítnutí odpovědnosti: 20 let stará paměť):

#define WANTIMP #define TYPE int #include "collection.h" #undef TYPE #define TYPE string #include "collection.h" #undef TYPE int main() { Collection_int lstInt; Collection_string lstString; } 

Kde jsem zapomněl přesnou magii preprocesoru uvnitř collection.h, ale bylo něco jako toto:

class Collection_ ## TYPE { public: Collection_ ## TYPE () {} void Add(TYPE value); private: TYPE *list; size_t n; size_t a; } #ifdef WANTIMP void Collection_ ## TYPE ::Add(TYPE value) #endif 

Komentáře

  • +1 – existuje kniha od Bjarne Stroustrup, kde vypráví historii C ++ (našel ji před lety v univerzitní knihovně) a tato technika byla výslovně popsána jako motivace pro vývoj šablon.
  • Má tato technika název? Možná " X-Macros " ?

Odpověď

The tradičním způsobem implementace generik bez použití generik (z důvodu vytvoření šablon) je použití ukazatele void.

typedef struct Item{ void* data; } Item; typedef struct Node{ Item Item; struct Node* next; struct Node* previous; } Node; 

V tomto příkladu kódu je binární strom nebo může být reprezentován dvojitě spojený seznam. Protože item zapouzdřuje ukazatel neplatnosti, lze tam uložit jakýkoli datový typ. Samozřejmě byste za běhu museli znát datový typ, abyste jej mohli vrhnout zpět na použitelný objekt.

Komentáře

  • To funguje pro obecné úložiště, ale co obecné funkce? Makra @gnat ' s to zvládnou, ale tato hrozná malá třída nemůže ' t. Vyhrál ' To také vedlo k noční můře přísných problémů s aliasingem při zpracování dat?
  • @MadScienceDreams Proč nemohl ' t to aplikujete na funkční adresy?
  • @IdeaHat: Ano, bylo by. Ale to vše pochází z doby, kdy byl kladen mnohem menší důraz na to, aby nástroje zachránily programátora před jeho vlastními chybami. Jinými slovy, musíte být opatrní, protože jazyk vám dal mnohem více provazu, abyste si mohli vystřelit do nohy.
  • Datový typ na druhém konci ukazatele můžete znát tak, že se někde uložíte .. … snad v tabulce? Možná … vtable? To je druh věcí, které pro nás kompilátor abstrahuje. Jinými slovy, než kompilátoři zpracovali šablony a polymorfismus, museli jsme si vytvořit vlastní.
  • @IdeaHat: U obecných funkcí se podívejte na qsort v knihovně C. Může třídit cokoli, protože bere ukazatel funkce pro funkci porovnání a předává dvojici void * ' s.

Odpověď

Jak zdůraznily další odpovědi, pro obecné datové struktury můžete použít void*.U jiných druhů parametrického polymorfismu byla použita preprocesorová makra, pokud se něco opakovalo hodně (jako desítkykrát). Abych byl upřímný, většinu času pro umírněné opakování lidé pouze zkopírovali a vložili a poté změnili typy, protože s makry je spousta nástrah, která je činí problematickými.

Opravdu potřebujeme název konverzace blub paradoxu , kde si lidé jen těžko dokáží představit programování v méně expresivním jazyce, protože toho se na tomto webu často vyskytuje. Pokud jste nikdy nepoužívali jazyk s expresivními způsoby implementace parametrického polymorfismu, opravdu nevíte, co vám chybí. Prostě přijmete kopírování a vkládání jako něco otravného, ale nezbytného.

Ve vašich současných jazycích, které si vyberete, jsou neefektivity, o kterých ještě nevíte. Za dvacet let se lidé budou divit, jak jste je odstranili. Krátká odpověď je, že jste to nevěděli, protože jste nevěděli, že můžete.

Komentáře

  • We really need a name for the opposite of the blub paradox, where people have a hard time imagining programming in a less expressive language, because this comes up a lot on this site. Zdá se mi to jako paradox blub (" Jazyky méně silné než Blub jsou zjevně méně silné, protože ' re chybí nějaká funkce, na kterou ' zvykl. ") ' by to měl být opak kdyby ten člověk znal omezení svého jazyka ' a dokázal si představit vlastnosti, které je řeší.
  • Naproti tomu není ' t docela dobré slovo, do kterého jsem se chystal, ale ' je to nejbližší, s čím jsem mohl přijít. Paradox blub předpokládá schopnost rozpoznat méně výkonný jazyk, ale ' nekomentuje obtížnost porozumění programování v jeden. Schopnost programovat ve výkonnějším jazyce poněkud neintuitivně nepřiznává ' odpovídající schopnost programovat v méně výkonném.
  • Mám podezření " konverzace " je slovo, které ' hledáte: " Situace, předmět nebo výrok, který je opakem jiného nebo mu odpovídá, ale s určitými transponovanými termíny "

Odpověď

Pamatuji si, když byl gcc dodáván s genclass – programem, který jako vstup vzal sadu typů parametrů ( např. klíč a hodnota pro Map) a speciální soubor syntaxe, který popsal parametrizovaný typ (řekněme Map nebo Vector) a vygeneroval platnou implementaci C ++ s vyplněnými typy param.

Takže pokud potřebné Map<int, string> a Map<string, string> (nejednalo se o skutečnou syntaxi), musíte spusťte tento program dvakrát a vygenerujte něco jako map_string_string.h a map_int_string.h a pak je použijte ve svém kódu.

na stránce genclass a dokumentace z GNU C ++ Library 2.0 , kde najdete další podrobnosti.

Odpověď

[OP: Nesnažím se tě osobně vyzvednout, ale zvýšit tvé i ostatní povědomí o uvažování o logice otázky ( s) zeptal se na SE a jinde. Neber to prosím osobně!]

Název otázky je dobrý, ale výrazně omezujete rozsah svých odpovědí zahrnutím „… situací, kdy potřebovaly generování kódu v době kompilace. „Na této stránce existuje mnoho dobrých odpovědí na otázku, jak provést generování kódu v C ++ bez šablon, ale k zodpovězení otázky, kterou jste původně položili:

Co lidé dělali před šablonami v C ++?

Odpověď je samozřejmě to, že jsme je (my) nepoužili. Ano, jsem na jazyku, ale zdá se, že podrobnosti otázky v těle (možná přehnaně) předpokládají, že každý miluje šablony a že bez nich by nikdy nebylo možné žádné kódování.

Jako příklad jsem dokončil mnoho mnoha projektů kódování v různých jazycích, aniž bych potřeboval generování kódu v době kompilace, a věřím, že to mají i ostatní. Problém vyřešený šablonami byl jistě dost velký na to, aby ho někdo skutečně poškrábal, ale scénář navrhovaný touto otázkou z velké části neexistoval.

Zvažte podobnou otázku v automobilech:

Jak řidiči přešli z jednoho rychlostního stupně na druhý pomocí automatizované metody, která za vás přeřadila, než byla vyvinuta automatická převodovka?

Otázka je samozřejmě hloupá. Zeptat se, jak člověk udělal X předtím, než bylo X vynalezeno, není opravdu platná otázka. Odpověď je obecně „my jsme to neudělali a nezmeškali jsme to, protože jsme nevěděli, že to vůbec bude existovat“.Ano, je snadné si všimnout výhody později, ale předpokládat, že všichni stáli kolem, kopali si za paty, čekali na automatický přenos nebo na šablony C ++, to opravdu není pravda.

Na otázku „jak řidiči zařadili rychlost před vynalezením automatické převodovky?“ Lze rozumně odpovědět „ručně“ a to je typ odpovědí, které zde dostáváte. Může to být dokonce typ otázky, kterou jste chtěli položit.

Ale nebyl to ten, na který jste se ptali.

Takže:

Otázka: Jak lidé používali šablony před vynalezením šablon?

Odpověď: Ne.

Otázka: Jak lidé používali šablony před vynalezením šablon, když potřebovali používat šablony ?

Odpověď: Nemuseli jsme je používat. Proč předpokládat, že jsme to udělali? (Proč předpokládat, že ano?)

Otázka: Jaké jsou alternativní způsoby, jak dosáhnout výsledků, které šablony poskytují?

Odpověď: Mnoho dobrých odpovědí existuje výše.

Před zveřejněním příspěvků prosím přemýšlejte o logických klamech ve svých příspěvcích.

[Děkujeme, prosím, zde zde není zamýšleno žádné poškození.]

Komentáře

  • Myslím, že jste ' je nepřiměřeně pedantský. OP nevyslovil jeho otázku tak dobře, jak by mohl. Nicméně si myslím, že ' je celkem jasné, že se chtěl zeptat něco jako " jak lidé dříve vytvářeli obecné funkce šablony ". Myslím, že v tomto případě by bylo vhodným krokem upravit jeho odpověď nebo zanechat komentář, spíše než spíše patronující přednášku.

Odpovědět

Hrozná makra mají pravdu, od http://www.artima.com/intv/modern2.html :

Bjarne Stroustrup: Ano. Když řeknete „typ šablony T“, je to opravdu starý matematický výraz „pro všechny T.“ Takhle se to zvažuje. Můj úplně první příspěvek o „C with Classes“ (který se vyvinul do C ++) z roku 1981 zmiňoval parametrizované typy. Tam jsem dostal problém správně, ale řešení jsem úplně špatně. Vysvětlil jsem, jak můžete parametrizovat typy pomocí maker a chlapce, který byl mizerný kód.

Zde vidíte, jak byla použita stará verze makra šablony. : http://www.xvt.com/sites/default/files/docs/Pwr++_Reference/rw/docs/html/toolsref/rwgvector.html

Odpověď

Jak již řekl Robert Harvey, ukazatel void je obecný datový typ.

Příklad ze standardní knihovny C, jak řadit pole double s obecným druhem:

double *array = ...; int size = ...; qsort (array, size, sizeof (double), compare_doubles); 

Kde compare_double je definován jako:

int compare_doubles (const void *a, const void *b) { const double *da = (const double *) a; const double *db = (const double *) b; return (*da > *db) - (*da < *db); } 

Podpis qsort je definován v stdlib.h:

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *) ); 

Všimněte si, že neexistuje žádný typ kontrola v době kompilace, dokonce ani v době běhu. Pokud seřadíte seznam řetězců pomocí výše uvedeného komparátoru, který očekává zdvojnásobení, bude se šťastně snažit interpretovat binární reprezentaci řetězce jako dvojitý a podle toho seřadit.

Odpovědět

Jedním ze způsobů, jak toho dosáhnout, je tento:

https://github.com/rgeminas/gp–/blob/master/src/scope/darray.h

#define DARRAY_DEFINE(name, type) DARRAY_TYPEDECL(name, type) DARRAY_IMPL(name, type) // This is one single long line #define DARRAY_TYPEDECL(name, type) \ typedef struct darray_##name \ { \ type* base; \ size_t allocated_mem; \ size_t length; \ } darray_##name; // This is also a single line #define DARRAY_IMPL(name, type) \ static darray_##name* darray_init_##name() \ { \ darray_##name* arr = (darray_##name*) malloc(sizeof(darray_##name)); \ arr->base = (type*) malloc(sizeof(type)); \ arr->length = 0; \ arr->allocated_mem = 1; \ return arr; \ } 

Makro DARRAY_TYPEDECL efektivně vytvoří definici struktury (v jednom řádku), která nahradí name se jménem, které předáte, a uložení pole type, které předáte (name je tam, abyste jej mohli zřetězit na základní název struktury a stále mít platný identifikátor – darray_int * není platný název pro strukturu), zatímco makro DARRAY_IMPL definuje funkce, které na této struktuře fungují (v takovém případě jsou označeny jako statické jen proto, aby definici zavolejte pouze jednou a neoddělujte vše).

Použije se jako:

#include "darray.h" // No types have been defined yet DARRAY_DEFINE(int_ptr, int*) // by this point, the type has been declared and its functions defined darray_int_ptr* darray = darray_int_ptr_init(); 

odpověď

Myslím si, že šablony si hodně zvykají jako způsob opětovného použití typů kontejnerů, které mají spousta algoritmických hodnot, jako jsou dynamická pole (vektory), třídění map, stromů atd.

Bez šablon jsou tyto implementace nutně psány obecně a jsou poskytovány jen s dostatečným množstvím informací o typu požadovaném pro jejich doménu. Například s vektorem potřebují pouze data, aby byla „schopná“ a potřebují znát velikost každé položky.

Řekněme, že máte třídu kontejnerů nazvanou Vector, která to dělá. Zabere to neplatnost *. Zjednodušené použití tohoto by bylo, aby kód aplikační vrstvy provedl hodně castingu. Pokud tedy spravují objekty Cat, musí seslat Cat * do anulace * a všude zpět. Odhazování kódu aplikace pomocí přetypování má zjevné problémy.

Šablony to vyřeší.

Další způsob, jak to vyřešit, je vytvořit vlastní typ kontejneru pro typ, který do kontejneru ukládáte. Takže pokud máte třídu Cat, můžete vytvořit třídu CatList odvozenou z Vectoru.Poté přetížíte několik metod, které používáte, a zavedete verze, které místo void * berou objekty Cat. Takže „d přetížíte metodu Vector :: Add (void *) s Cat :: Add (Cat *), která interně jednoduše předá parametr Vector :: Add (). Pak v kódu aplikace zavoláte přetížená verze Add při předávání objektu Cat a vyhnout se tak castingu. Abychom byli spravedliví, metoda Add by nevyžadovala přetypování, protože objekt Cat * se převede na void * bez přetypování. Ale metoda pro načtení položky, jako je přetížení indexu nebo metoda Get (), bude.

Dalším přístupem, jehož jediným příkladem, který si pamatuji z počátku 90. let s velkým aplikačním rámcem, je použití vlastního nástroje, který vytváří tyto typy nad třídami. Věřím, že to udělal MFC. Měli různé třídy pro kontejnery jako CStringArray, CRectArray, CDoulbeArray, CIntArray atd. Spíše než udržovat duplicitní kód, udělali nějaký typ metaprogramování podobný makrům, pomocí externího nástroje, který by generoval třídy. Nástroj zpřístupnili pomocí Visual C ++ pro každého Chtěl jsem to použít – nikdy jsem to neudělal. Možná jsem měl. Ale v té době experti hovořili „Sane podmnožina C ++“ a „Ty nepotřebuješ šablony“

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *