Kommentit
- tämä tehtiin todennäköisesti samalla tavalla kuin tavallisessa C: ssä ”878082a206″>
Yleiskoodin kirjoittaminen, kun kohde on C-kääntäjä
Vastaa
Robertin vastauksessa katetun void *
-osoittimen lisäksi käytettiin tällaista tekniikkaa (Vastuuvapauslauseke: 20 vuotta vanha muisti):
#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; }
Mistä olen unohtanut tarkan esiprosessorin taikuuden collection.h
sisällä, mutta se oli jotain tällaista:
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
kommentit
- +1 – Bjarne Stroustrupin kirja hän kertoo C ++: n historian (löysi sen vuosia sitten yliopiston kirjastosta), ja tätä tekniikkaa kuvattiin nimenomaisesti motivaationa mallien kehittämiselle.
- Onko tällä tekniikalla nimeä? Ehkä " X-makrot " ?
Vastaa
perinteinen tapa toteuttaa geneerisiä aineita ilman geneerisiä aineita (syyt mallien luomiseen) on käyttää void-osoitinta.
typedef struct Item{ void* data; } Item; typedef struct Node{ Item Item; struct Node* next; struct Node* previous; } Node;
Tässä esimerkkikoodissa binääripuu tai kaksinkertaisesti linkitetty luettelo voidaan edustaa. Koska item
kapseloi tyhjän osoittimen, siihen voidaan tallentaa mitä tahansa tietotyyppiä. Tietysti sinun on tiedettävä tietotyyppi ajon aikana, jotta voit heittää sen takaisin käytettäväksi objektiksi.
Kommentit
- Se toimii geneeriselle tallennukselle, mutta entä yleiset toiminnot? @gnat ' s makrot voivat hoitaa sen, mutta tämä kauhea pieni luokka voi ' t. Voitti ' t, mikä johti myös painajaisiin, jotka aiheuttivat tiukkoja aliasing-ongelmia tietojen käsittelyn aikana?
- @MadScienceDreams Miksi ' t käytätkö tätä funktion osoitteisiin?
- @IdeaHat: Kyllä, se olisi. Mutta kaikki tämä tulee ajasta, jolloin korostettiin paljon vähemmän sitä, että työkalut pelastavat ohjelmoijan omista virheistään. Toisin sanoen sinun oli oltava varovainen, koska kieli antoi sinulle paljon enemmän köyttä ampumaan itsesi jalkaan.
- Voit tietää tietotyypin osoittimen toisesta päästä tallentamalla jonnekin .. ehkä pöydässä? Ehkä … vtable? Tämä on sellainen juttu, jonka kääntäjä tiivistää meille. Toisin sanoen, ennen kuin kääntäjät käsittelivät malleja ja polymorfismia, meidän oli tehtävä omat.
- @IdeaHat: Katso yleisiä toimintoja tarkastelemalla qsortia C-kirjastossa. Se voi lajitella mitä tahansa, koska se vie funktiosoittimen vertailutoiminnolle ja välittää pari tyhjiä * ' s.
Vastaus
Kuten muut vastaukset huomauttivat, voit käyttää yleisiä tietorakenteita void*
.Muiden parametristen polymorfismien tapauksessa esiprosessorimakroja käytettiin, jos jokin toistui paljon (kuten kymmeniä kertoja). Ollakseni rehellinen, tosin suurimman osan ajasta maltilliseen toistoon ihmiset vain kopioivat ja liittivät, muuttuivat sitten tyyppejä, koska makroilla on paljon karhuja, jotka tekevät niistä ongelmallisia.
Tarvitsemme todella nimi blub-paradoksin käänteelle, jossa ihmisten on vaikea kuvitella ohjelmointia vähemmän ilmeikkäällä kielellä, koska tämä tulee esiin paljon tällä sivustolla. Jos et ole koskaan käyttänyt kieltä, jolla on ilmeikäs tapoja toteuttaa parametrinen polymorfismi, et todellakaan tiedä mitä puuttuu. Hyväksyt vain kopioinnin ja liittämisen hieman ärsyttäväksi, mutta välttämättömäksi.
Nykyisillä kielilläsi on tehottomuutta, josta et ole edes tietoinen. Kahdenkymmenen vuoden kuluttua ihmiset ihmettelevät, kuinka sinä eliminoit heidät. Lyhyt vastaus on, ettet t, koska et tiennyt.
Kommentit
-
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.
Se tuntuu minusta täsmälleen blub-paradoksilta (" Blubia vähemmän voimakkaat kielet ovat ilmeisesti vähemmän tehokkaita, koska ne ' uudelleen puuttuu jokin ominaisuus, johon hän ' tottunut. ") Se ' d on päinvastainen jos henkilö tietäisi kielensä ' rajoitukset ja voisi kuvitella piirteet, jotka ratkaisevat ne. - Vastakohta ei ole ' t aivan sanan, jota aioin, mutta se ' on lähin mitä keksin. Blub-paradoksi olettaa kyvyn tunnistaa vähemmän tehokas kieli, mutta ei ' t kommentoi ohjelmoinnin ymmärtämisen vaikeutta yksi. Hieman haitallisesti kyky ohjelmoida tehokkaammalla kielellä ei anna ' t vastaavaa kykyä ohjelmoida vähemmän tehokkaalla kielellä.
- Epäilen, että " converse " on sana, jota ' etsit: " Tilanne, esine tai lause, joka on toisen käänteinen tai vastaa sitä, mutta tietyillä termeillä siirretty "
Vastaus
Muistan, kun gcc toimitettiin genclass
– ohjelman kanssa, joka otti syötteeksi joukon parametrityyppejä ( esim. avain ja arvo kartalle) ja erityinen syntaksitiedosto, joka kuvaa parametrisoitua tyyppiä (esimerkiksi kartta tai vektori) ja loi kelvolliset C ++ -toteutukset parametrityyppien ollessa täytettyjä.
Joten jos tarvitaan Map<int, string>
ja Map<string, string>
(tämä ei ollut varsinainen syntakse, muista) Suorita kyseinen ohjelma kahdesti generoidaksesi jotain map_string_string.h ja map_int_string.h ja käytä sitten näitä koodissasi.
Katso iv id
-sivulta = ”ebaedd2ca2″>
ja -dokumentaatio GNU C ++ Library 2.0: sta saadaksesi lisätietoja.
Vastaa
[OP: lle: En yritä valita sinua henkilökohtaisesti, mutta kasvatan sinun ja muiden tietoisuutta ajatella kysymyksen logiikkaa ( s) kysyi SE: ltä ja muualta. Älä ota tätä henkilökohtaisesti!]
Kysymyksen otsikko on hyvä, mutta rajoitat ankarasti vastausten laajuutta sisällyttämällä ”… tilanteita, joissa he tarvitsivat kääntöaikakoodia. ”Tällä sivulla on monia hyviä vastauksia kysymykseen siitä, miten käännösaikakoodit luodaan C ++: ssa ilman malleja, mutta vastaamaan alun perin esittämäsi kysymykseen:
Mitä ihmiset tekivät ennen C ++: n malleja?
Vastaus on tietysti, että he (emme) käyttäneet niitä. Kyllä, olen kielellä poskessa, mutta kehon kysymyksen yksityiskohdat näyttävät (ehkä liioiteltuja) olettavan, että kaikki rakastavat malleja ja että koodausta ei olisi koskaan voitu tehdä ilman niitä.
Esimerkiksi olen suorittanut monia monia koodausprojekteja eri kielillä tarvitsematta kääntöaikakoodien luomista, ja uskon, että myös muut ovat. Toki mallien ratkaisema ongelma oli tarpeeksi suuri kutina, jotta joku todella naarmuuntui siihen, mutta tämän kysymyksen esittämää skenaariota ei ollut lainkaan.
Harkitse vastaavaa kysymystä autoissa:
Kuinka kuljettajat siirtyivät vaihdosta toiseen käyttämällä automaattista menetelmää, joka vaihtoi vaihdetta puolestasi, ennen kuin automaattivaihteisto keksittiin?
Kysymys on tietysti typerä. Kysymys siitä, miten henkilö teki X: n ennen X: n keksimistä, ei ole oikea pätevä kysymys. Vastaus on yleensä: ”Emme tehneet sitä emmekä unohtaneet sitä, koska emme tienneet, että sitä olisi koskaan olemassa”.Kyllä, on helppo nähdä etu tosiseikoista, mutta olettaa, että kaikki seisoivat ympärillään, potkivat kantaansa, odottivat automaattivaihteistoa tai C ++ -malleja, ei todellakaan ole totta.
Kysymykseen ”miten kuljettajat vaihtoivat vaihteita ennen kuin automaattivaihteisto keksittiin?”, Voidaan kohtuudella vastata ”manuaalisesti”, ja juuri tämän tyyppisiä vastauksia saat täällä. Se voi olla jopa sellainen kysymys, jonka tarkoitit kysyä.
Mutta se ei ollut se, jota kysyit.
Joten:
K: Kuinka ihmiset käyttivät malleja ennen mallien keksimistä?
A: Emme tehneet.
K: Kuinka ihmiset käyttivät malleja ennen mallien keksimistä, kun heidän tarvitsi käytä malleja ?
V: Meidän ei tarvinnut käyttää niitä. Miksi oletetaan, että käytimme? (Miksi olettaa, että käytämme?)
K: Mitkä ovat vaihtoehtoisia tapoja saavuttaa mallien tarjoamat tulokset?
V: Edellä on monia hyviä vastauksia.
Ajattele loogisia virheitä viesteissäsi ennen lähettämistä.
[Kiitos! Ole hyvä, älä haittaa tässä.]
Kommentit
- Luulen, että ' on perusteettoman pedanttinen. OP ei muotoillut kysymystään niin hyvin kuin hänellä olisi voinut olla. Mielestäni on kuitenkin ' melko selvää, että hän halusi kysyä jotain " miten ihmiset loivat yleisiä toimintoja ennen mallit ". Mielestäni tässä tapauksessa asianmukainen toimenpide olisi ollut hänen vastauksensa muokkaaminen tai kommentin jättäminen pikemminkin holhoavan luennon pitämisen sijaan.
Vastaus
Kauheat makrot ovat oikeassa, alkaen http://www.artima.com/intv/modern2.html :
Bjarne Stroustrup: Kyllä. Kun sanot ”mallityyppi T”, se on oikeastaan vanha matemaattinen ”kaikille T.” Sitä pidetään. Ensimmäinen artikkelini ”C with Classes” (josta kehittyi C ++) vuodelta 1981 mainitsi parametrisoidut tyypit. Siellä sain ongelman oikein, mutta sain ratkaisun täysin väärin. Selitin, kuinka voit parametroida tyypit makroilla ja poika, joka oli surkea koodi.
Näet kuinka mallin vanhaa makroversiota käytettiin täällä : http://www.xvt.com/sites/default/files/docs/Pwr++_Reference/rw/docs/html/toolsref/rwgvector.html
Vastaa
Kuten Robert Harvey jo sanoi, tyhjä osoitin on yleinen tietotyyppi.
Esimerkki tavallisesta C-kirjastosta, kuinka kaksoisryhmä lajitellaan yleisen lajittelun kanssa:
double *array = ...; int size = ...; qsort (array, size, sizeof (double), compare_doubles);
Missä compare_double
määritellään seuraavasti:
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); }
qsort
-allekirjoitus määritetään stdlib.h-tiedostossa:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *) );
Huomaa, että tyyppiä ei ole tarkistus käännösajassa, ei edes ajon aikana. Jos lajittelet luettelon merkkijonoista yllä olevan vertailijan kanssa, joka odottaa kaksinkertaistumista, se yrittää mielellään tulkita merkkijonon binäärisen esityksen kaksinkertaiseksi ja lajitella sen mukaan.
Yksi tapa tehdä tämä on seuraava:
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; \ }
DARRAY_TYPEDECL-makro luo tehokkaasti rakennemäärityksen (yhdellä rivillä) korvaamalla name
antamallasi nimellä ja tallentamalla välitetyn type
-taulukon (name
on siellä, jotta voit liittää sen perusrakenteen nimelle ja niillä on edelleen kelvollinen tunniste – darray_int * ei ole kelvollinen nimi strukturille), kun taas DARRAY_IMPL-makro määrittelee kyseisellä rakenteella toimivat toiminnot (siinä tapauksessa ne ”merkitään staattisiksi vain siten, että kutsu määritelmää vain kerran, älä erota kaikkea).
Tätä käytetään nimellä:
#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();
vastaus
Luulen, että mallit käyttävät paljon tapana käyttää uudelleen sellaisia säilötyyppejä, joilla on paljon algoritmiarvoja, kuten dynaamiset matriisit (vektorit), kartat, puut jne. lajittelu jne.
Ilman malleja, nämä sisältävät välttämättä toteutuksia, ne kirjoitetaan yleisesti ja niille annetaan juuri tarpeeksi tietoa heidän verkkotunnukselleen vaaditusta tyypistä. Esimerkiksi vektorilla he tarvitsevat vain tiedot, jotta ne ovat ”kelvollisia” ja heidän on tiedettävä jokaisen kohteen koko.
Oletetaan, että sinulla on Vector-niminen säilöluokka, joka tekee tämän. Se on mitätön *. Tämän yksinkertaistettu käyttö merkitsisi sitä, että sovelluskerroskoodi tekee paljon suoratoistoa. Joten jos he hallitsevat kissaobjekteja, heidän on heitettävä kissa * tyhjäksi * ja takaisin kaikkialle. Sovelluskoodin tyhjentämisellä suoratoistoilla on ilmeisiä ongelmia.
Mallit ratkaisevat tämän.
Toinen tapa ratkaista se on luoda mukautettu säilötyyppi sille tyypille, jonka tallennat säilöön. Joten jos sinulla on Cat-luokka, luodaan CatList-luokka, joka on johdettu Vectorista.Tämän jälkeen ylikuormitat muutaman käyttämäsi menetelmän ja otat käyttöön versiot, jotka ottavat Cat-objekteja tyhjien * sijaan. Joten ylikuormitat Vector :: Add (void *) -menetelmää Cat :: Add (Cat *): lla, joka välittää parametrin yksinkertaisesti Vector :: Add (): lle. Sitten kutsut sovelluskoodissasi ylikuormitettu Add-versio, kun välität Cat-objektin, ja vältä siten heittämistä. Ollakseni oikeudenmukainen, Lisää-menetelmä ei vaadi näyttelijöitä, koska Cat * -objekti muuntuu mitätöitäväksi * ilman näyttelijää. Mutta menetelmä kohteen noutamiseksi, kuten indeksin ylikuormitus tai Get () -menetelmä, tekisi. >
Toinen lähestymistapa, jonka muistan vain 90-luvun alusta ja jolla on suuri sovelluskehys, on käyttää mukautettua apuohjelmaa, joka luo nämä tyypit luokkiin. Uskon, että MFC teki tämän. Heillä oli erilaisia luokkia kontteille kuten CStringArray, CRectArray, CDoulbeArray, CIntArray jne. Sen sijaan, että ylläpitävät kaksoiskoodia, he tekivät jonkinlaisen meta-ohjelmoinnin kuin makrot, käyttäen ulkoista työkalua, joka luokkaan luodaan. He tekivät työkalun saataville Visual C ++: n kanssa, jos joku halusin käyttää sitä – en koskaan tehnyt. Ehkä minun olisi pitänyt. Mutta tuolloin asiantuntijat mainitsivat: ”C ++: n järkevä osajoukko” ja ”Sinun ei tarvitse malleja”