Mit csináltak az emberek a C ++ sablonjai előtt? [duplicate]

Erre a kérdésre már itt vannak válaszok :

megjegyzések

  • ezt valószínűleg ugyanúgy tették, mint a sima C-ben, lásd: Általános kód írása, ha a cél egy C fordító
  • @Telastyn, IIRC, sablonok a CFront 3 (kb. 1990) újdonságai voltak.
  • @Telastyn: 2000 körül a legtöbb létező C ++ fordító nem nyújtott túl jól sablonokat (még akkor is, ha úgy tettek, mintha szolgáltatnák, a legtöbbjük túl hibás volt a gyártás használatához). A sablonok támogatása többnyire az általános tárolók támogatására vonatkozott, de messze nem az Alexandrescu ' s " Modern C ++ design " példák.
  • Biztos benne, hogy a fordítási idejű kódgenerálást használták, mielőtt a sablonok ereje megvalósult volna? Akkor fiatal voltam, de az a benyomásom, hogy régen csak a fordításidejű kódok előállításának legegyszerűbb fajtáit használták. Ha valóban programot szeretett volna írni a program megírásához, akkor egy programot / szkriptet írt, amelynek kimenete C forráskód volt, ahelyett, hogy ezt sablonnyelvvel csinálta volna.
  • @Joshua – A kérdések duplikátumként vannak lezárva, ha egy másik kérdésre adott válaszok a jelen kérdés mögött álló elsődleges kérdésekre irányulnak. " Pontos " egyezésre nincs szükség; a lényeg az, hogy gyorsan összeegyeztessük az OP-t a kérdésükre adott válaszokkal. Más szóval, igen, ez ' egy másolat. Ez azt jelenti, hogy ez a kérdés az " OMG-t kapja! Hogyan létezett a Világ korábban …?! " ami nem ' egy rettenetesen konstruktív kérdés. Brown doktor egy korábbi (és most törölt megjegyzésében) rámutatott arra, hogy ez a jelenség hogyan befolyásolhatja a kommentárokat.

Válasz

A void * mutató mellett, amelyre Robert válaszában vonatkozik , ehhez hasonló technikát alkalmaztak (Jogi nyilatkozat: 20 éves emlék):

#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; } 

Ahol elfelejtettem a pontos előfeldolgozó varázslatot collection.h belül valami ilyesmi:

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 

Megjegyzések

  • +1 – Van Bjarne Stroustrup könyve, ahol elmondja a C ++ történetét (évekkel ezelőtt talált rá az egyetemi könyvtárban), és ezt a technikát kifejezetten a sablonok fejlesztésének motivációjaként írták le.
  • Van ennek a technikának neve? Talán " X-makrók " ?

Válasz

A A generikumok generikus megvalósításának hagyományos módja (a sablonok létrehozásának oka) egy void mutató használata.

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

Ebben a példakódban egy bináris fa ill. duplán linkelt lista képviselhető. Mivel a item egy érvénytelen mutatót foglal magában, ezért bármilyen adattípus tárolható. Természetesen futás közben ismernie kell az adattípust, hogy újra felhasználható objektummá tudja dobni.

Megjegyzések

  • Ez működik általános tároláshoz, de mi a helyzet az általános funkciókkal? @gnat ' s makrók képesek ezt kezelni, de ez a borzalmas kis osztály ' t. Nyert ' t ez is szigorú álnevezési problémák rémálmához vezetett az adatok feldolgozása közben?
  • @MadScienceDreams Miért nem lehet ' t alkalmazod ezt a függvény címekre?
  • @IdeaHat: Igen, megtenné. De mindez abból az időből származik, amikor sokkal kevesebb hangsúlyt fektettek arra, hogy az eszközök mentik meg a programozót a saját hibáitól. Más szavakkal, óvatosnak kellett lennie, mert a nyelv sokkal több kötelet adott a lábra lövéshez.
  • Az adattípust a mutató másik végén ismerhette meg, ha valahová tárolja .. talán egy táblázatban? Talán egy … vtable? Ez az a fajta dolog, amit a fordító elvonatkoztat számunkra. Más szavakkal, mielőtt a fordítók kezelnék a sablonokat és a polimorfizmust, saját magunkat kellett elkészítenünk.
  • @IdeaHat: Az általános függvényekért nézze meg a qsort a C könyvtárban. Bármit rendezhet, mert függvénymutatót vesz az összehasonlító függvényhez, és átenged egy pár érvénytelen * ' s párost.

Válasz

Amint más válaszok rámutattak, a void* elemet használhatja általános adatstruktúrákhoz.Más típusú paraméteres polimorfizmus esetén előfeldolgozó makrókat használtak, ha valami sok t megismételt (például több tucatszor). Hogy őszinte legyek, a legtöbbször a mérsékelt ismétléshez az emberek csak másoltak és beillesztettek, majd megváltoztatták a típusokat, mert sok olyan makróval járó buktató van, amely problémássá teszi őket.

Nagyon szükségünk van egy a blub paradoxon beszélgetésének neve, ahol az emberek nehezen tudják elképzelni a kevésbé kifejező nyelvű programozást, mert ez sokat felmerül ezen a webhelyen. Ha még soha nem használt olyan nyelvet, amely kifejező módon alkalmazta a parametrikus polimorfizmust, akkor nem igazán tudja, mi hiányzik. Ön csak elfogadja, hogy a másolás és beillesztés kissé bosszantó, de szükséges.

A választott nyelven vannak olyan hatékonysághiányok, amelyekről még nem is tud. Húsz év múlva az emberek kíváncsi lesznek arra, hogyan szüntették meg őket. A rövid válasz az, hogy nem tudtad, mert nem tudtad.

Megjegyzések

  • 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. Ez pont a blub paradoxonnak tűnik számomra (" A Blubnál kevésbé hatékony nyelvek nyilván kevésbé hatékonyak, mert ' újra hiányzik valami olyan funkció, amihez ' szokott. ") ' d az ellenkezője ha az illető tudná a nyelvét ' s korlátai és el tudna képzelni olyan funkciókat, amelyek megoldják ezeket.
  • Szemben van nem ' t eléggé az a szó, amire gondoltam, de ' s ez a legközelebb, amivel elő tudtam állni. A blub paradoxon feltételezi a kevésbé hatékony nyelv felismerésének képességét, de ' nem kommentálja a programozás megértésének nehézségeit a egy. Némileg ellenintézkedésképpen a nagyobb teljesítményű nyelven történő programozás képessége ' nem biztosít megfelelő teljesítményt egy kevésbé hatékony nyelvű programozáshoz.
  • gyanítom, hogy " converse " az a szó, amelyet ' keres: " Olyan helyzet, objektum vagy utasítás, amely egy másik fordítottja vagy annak felel meg, de bizonyos kifejezésekkel átültetik "

Válasz

Emlékszem, amikor a gcc a genclass csomaggal érkezett – egy program, amely paramétertípust vett be bemenetként ( pl. kulcs és érték a térképhez), valamint egy speciális szintaxis fájl, amely leírta a paraméterezett típust (mondjuk egy térképet vagy egy vektorot), és érvényes C ++ megvalósításokat generált a kitöltött param típusokkal.

Tehát, ha szükséges Map<int, string> és Map<string, string> (ez nem volt a tényleges szintaxis, ne feledd) futtassa ezt a programot kétszer, hogy létrehozzon olyanokat, mint a map_string_string.h és a map_int_string.h, majd használja ezeket a kódjában.

Lásd a kézikönyvet a genclass és a dokumentáció a GNU C ++ Library 2.0-ról további részletekért.

Válasz

[Az OP-hez: Nem próbálok személyesen kiválasztani téged, hanem felhívom az ön és mások figyelmét arra, hogy gondolkodjak a kérdés logikáján ( s) kérdezték SE-n és másutt. Kérem, ne vegye ezt személyesen!]

A kérdés címe jó, de szigorúan korlátozza válaszai körét azáltal, hogy “… olyan helyzetekkel egészíti ki, amikor fordítási idő kód létrehozására van szükségük. “Sok jó válasz van arra a kérdésre, hogy miként lehet fordítási idő kódot generálni a C ++ – ban sablonok nélkül, de ezen a lapon válaszolni lehet az eredetileg feltett kérdésre:

Mit tettek az emberek a C ++ sablonjai előtt?

A válasz természetesen az, hogy (mi) nem használtuk őket. Igen, nyelvpofás vagyok, de a kérdés részletei a testben úgy tűnik (talán eltúlzottan) azt feltételezik, hogy mindenki szereti a sablonokat, és nélkülük soha nem lehetett volna kódolni.

Példaként sokféle kódolási projektet végeztem el különféle nyelveken anélkül, hogy fordításidejű kód generálásra lett volna szükségem, és úgy gondolom, hogy másoknak is. Persze, a sablonokkal megoldott probléma elég nagy viszketés volt ahhoz, hogy valaki valóban megkarcolta, de a kérdés által felvetett forgatókönyv nagyrészt nem létezett.

Vegyünk egy hasonló kérdést az autóknál:

Hogyan váltottak az illesztőprogramok egyik sebességről a másikra egy automatizált módszer segítségével, amely az Ön sebességváltását váltotta meg, mielőtt feltalálták volna az automatikus sebességváltót?

A kérdés természetesen buta. Arra a kérdésre, hogy egy személy hogyan csinálta X-et, mielőtt X-et feltalálták, nem igazán érvényes kérdés. A válasz általában az, hogy “nem” tettük meg és nem hiányoltuk, mert nem tudtuk, hogy valaha is létezik “.Igen, könnyű belátni a tény utáni előnyöket, de feltételezni, hogy mindenki körül állt, rugdosta a sarkát, várt az automatikus sebességváltóra vagy a C ++ sablonokra, valójában nem igaz.

Arra a kérdésre, hogy “hogyan váltották a vezetők a sebességváltót, mielőtt feltalálták volna az automatikus sebességváltót?” Ésszerűen válaszolhatunk “manuálisan”, és ez a típusú válasz, amelyet itt kaptok. Lehet, hogy még az a típusú kérdés is, amelyet feltettél.

De nem az volt a kérdés, amit feltettél.

Tehát:

K: Hogyan használták az emberek a sablonokat a sablonok feltalálása előtt?

V: Nem.

K: Hogyan használták az emberek a sablonokat a sablonok feltalálása előtt, amikor nekik kellett használjon sablonokat ?

V: Nem kellett nek használnunk őket. Miért feltételezzük, hogy mi tettük? (Miért feltételezzük, hogy mi csináljuk?)

K: Milyen alternatív módszerekkel lehet elérni a sablonok által nyújtott eredményeket?

V: Sok jó válasz létezik fent.

Kérjük, gondoljon a logikai tévedésekre a bejegyzéseiben, mielőtt feladna.

[Köszönöm! Kérem, ne okozzon itt semmi kárt.]

Megjegyzések

  • Szerintem ' indokolatlanul pedáns. Az OP nem fogalmazta meg annyira a kérdését, mint amennyire csak lehetett volna. Azt hiszem azonban, hogy ' nagyon világos, hogy meg akarja kérdezni olyasmi, mint " hogyan hoztak létre az emberek általános funkciókat korábban sablonok ". Úgy gondolom, hogy ebben az esetben a megfelelő lépés a válasz szerkesztése vagy a megjegyzés hagyása lett volna, nem pedig inkább pártfogó előadás.

Válasz

A szörnyű makróknak igaza van, http://www.artima.com/intv/modern2.html -tól:

Bjarne Stroustrup: Igen. Amikor azt mondja, hogy “T típusú sablon”, ez valójában a régi matematikai, “minden T-re”. Ez így van. Az első cikkem a “C osztályokkal” -ról (amely C ++ -vá fejlődött) 1981-től kezdve paraméterezett típusokat említett. Ott jól értettem a problémát, de a megoldást teljesen rosszul. Elmagyaráztam, hogyan lehet paraméterezni a típusokat makrókkal, és egy fiúval, ami silány kód volt.

Itt láthatja, hogyan használták a sablon régi makró verzióját. : http://www.xvt.com/sites/default/files/docs/Pwr++_Reference/rw/docs/html/toolsref/rwgvector.html

Válasz

Ahogy Robert Harvey már mondta, az érvénytelen mutató az általános adattípus.

Példa a standard C könyvtárból, hogyan lehet kettős tömböt rendezni egy általános rendezéssel:

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

Ahol a compare_double a következő:

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); } 

A qsort aláírása az stdlib.h fájlban van meghatározva:

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

Vegye figyelembe, hogy nincs típus fordításkor, futás közben sem. Ha a fenti összehasonlítóval sorba rendez egy olyan karakterlánc-listát, amely duplázásra számít, az örömmel megpróbálja kettősként értelmezni a karakterlánc bináris ábrázolását, és ennek megfelelően rendezni.

Válasz

Ennek egyik módja a következő:

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; \ } 

A DARRAY_TYPEDECL makró hatékonyan létrehoz egy struktúra definíciót (egyetlen sorban), helyettesítve a name az átadott névvel, és az átadott type tömb tárolása (a name ott található, hogy összefűzze az alap struktúra nevéhez, és még mindig rendelkezik érvényes azonosítóval – a darray_int * nem egy struktúra érvényes neve), míg a DARRAY_IMPL makró meghatározza az adott struktúrán működő függvényeket (ebben az esetben csak statikusan jelölik meg, hogy az ember csak egyszer hívja meg a definíciót, és ne különítsen el mindent).

Ezt használnák:

#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(); 

Válasz

Úgy gondolom, hogy a sablonok sokat használják, hogy újból felhasználhassák a sok algoritmikus érték, például dinamikus tömbök (vektorok), térképek, fák, stb. rendezés stb.

Sablonok nélkül szükségszerűen ezek tartalmazzák a megvalósításokat általános módon írják, és éppen elegendő információt kapnak a domainjükhöz szükséges típusról. Például egy vektorral csak az adatoknak kell lenniük, hogy “blatt” legyenek, és tudnia kell az egyes elemek méretét.

Mondjuk azt, hogy van egy Vector nevű tároló osztálya, amely ezt elvégzi. Érvénytelen *. Ennek leegyszerűsített használata az lenne, ha az alkalmazási réteg kódja sok castingot végezne. Tehát, ha Cat objektumokat kezelnek, akkor Cat * -t el kell vetniük az ürességbe *, és vissza az egész helyre. Az alkalmazási kód szemetelésével nyilvánvaló problémák vannak.

A sablonok megoldják ezt.

A megoldás másik lehetősége egy egyedi tárolótípus létrehozása a tárolóban tárolt típushoz. Tehát ha van Cat osztályod, létrehozhatsz egy CatList osztályt, amely a Vector-ból származik.Ezután túlterheli az általad használt néhány módszert, és olyan verziókat vezet be, amelyek a void * helyett Cat objektumokat vesznek fel. Tehát túlterheli a Vector :: Add (void *) metódust a Cat :: Add (Cat *) paranccsal, amely belsőleg egyszerűen átadja a paramétert a Vector :: Add () fájlnak. Ezután az alkalmazáskódjában meghívja a Cat túlterhelt változata, amikor áthalad egy Cat objektumon, és ezzel elkerülhető a dobás. Hogy igazságos legyek, az Add metódushoz nem lesz szükség castingra, mert a Cat * objektum casting nélkül konvertálódik érvénytelenné. De az elem lekérésére szolgáló módszer, például az index túlterhelése vagy a Get () metódus. >

A másik megközelítés, amelynek egyetlen példáját a 90-es évek elejéről emlékszem nagy alkalmazási keretrendszerrel, egy olyan egyedi segédprogram használata, amely ezeket a típusokat osztályok fölé hozza létre. Úgy gondolom, hogy az MFC ezt csinálta. Különböző osztályaik voltak mint a CStringArray, a CRectArray, a CDoulbeArray, a CIntArray stb. A duplikált kód fenntartása helyett a makrókhoz hasonló meta-programozást végeztek, az osztályokat létrehozó külső eszköz segítségével. Az eszközt elérhetővé tették a Visual C ++ programmal, ha valaki használni akartam – soha nem tettem. Talán kellett volna. De abban az időben a szakértők a “C ++ épelméjű részhalmazát” és a “Nincs szükséged sablonokra”

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük