Cosa facevano le persone prima dei modelli in C ++? [duplicate]

Questa domanda ha già una risposta qui :

Commenti

  • questo probabilmente è stato fatto allo stesso modo del C semplice, vedi Scrivere codice generico quando lobiettivo è un compilatore C
  • @Telastyn, IIRC, i modelli erano una novità di CFront 3 (circa 1990).
  • @Telastyn: intorno allanno 2000, la maggior parte dei compilatori C ++ esistenti non fornivano modelli molto bene (anche se pretendevano di fornirli, la maggior parte di essi era troppo buggata per luso in produzione). Il supporto dei modelli era principalmente per supportare contenitori generici, ma lontano dai requisiti per supportare qualcosa come Alexandrescu ' s " Design C ++ moderno " esempi.
  • Sei sicuro che la generazione del codice in fase di compilazione fosse utilizzata prima che la potenza dei modelli fosse realizzata? Allora ero giovane, ma ho limpressione che ai vecchi tempi si usassero solo i tipi più semplici di generazione di codice in fase di compilazione. Se volevi davvero scrivere un programma per scrivere il tuo programma, hai scritto un programma / script il cui output era il codice sorgente C, piuttosto che farlo con il linguaggio dei modelli.
  • @Joshua – Le domande sono chiuse come duplicate se le risposte esistenti a unaltra domanda affrontano le domande principali alla base della presente domanda. " Le corrispondenze " esatte non sono obbligatorie; il punto è abbinare rapidamente il PO con le risposte alla loro domanda. In altre parole, sì, ' è un duplicato. Detto questo, questa domanda sa di " OMG! Comera il mondo prima …?! " che non è ' una domanda estremamente costruttiva. Doc Brown ha sottolineato in un precedente (e ora eliminato commento) come quel fenomeno possa influenzare il commento.

Risposta

Oltre al void * puntatore coperto nella risposta di Robert , è stata utilizzata una tecnica come questa (Dichiarazione di non responsabilità: Memoria di 20 anni):

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

Dove ho dimenticato lesatta magia del preprocessore allinterno di collection.h, ma era qualcosa del genere:

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 

Commenti

  • +1 – Cè un libro di Bjarne Stroustrup dove racconta la storia del C ++ (trovato anni fa nella biblioteca delluniversità), e questa tecnica è stata esplicitamente descritta come una motivazione per lo sviluppo di modelli.
  • Questa tecnica ha un nome? Forse " X-Macros " ?

Risposta

Il il modo tradizionale per implementare i generici senza generici (il motivo per cui sono stati creati i modelli) è usare un puntatore void.

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

In questo codice di esempio, un albero binario o può essere rappresentato un elenco a doppio collegamento. Poiché item incapsula un puntatore vuoto, qualsiasi tipo di dati può essere memorizzato lì. Ovviamente, dovresti conoscere il tipo di dati in fase di esecuzione in modo da poterlo restituire a un oggetto utilizzabile.

Commenti

  • Funziona per larchiviazione generica, ma per quanto riguarda le funzioni generiche? Le macro di @gnat ' possono gestirlo, ma questa orribile piccola classe può ' t. Ha vinto ' anche questo ha portato a un incubo di problemi di aliasing durante lelaborazione dei dati?
  • @MadScienceDreams Perché non poteva ' lo applichi agli indirizzi delle funzioni?
  • @IdeaHat: Sì, lo sarebbe. Ma tutto questo deriva da unepoca in cui cera molta meno enfasi sul fatto che gli strumenti salvassero il programmatore dai propri errori. In altre parole, dovevi stare attento perché la lingua ti dava molta più corda per spararti ai piedi.
  • Potresti conoscere il tipo di dati allaltra estremità del puntatore memorizzandolo da qualche parte .. forse in un tavolo? Forse un … vtable? Questo è il genere di cose che il compilatore estrae per noi. In altre parole, prima che i compilatori gestissero i modelli e il polimorfismo, dovevamo crearne uno nostro.
  • @IdeaHat: per le funzioni generiche guarda qsort nella libreria C. Può ordinare qualsiasi cosa perché prende un puntatore a funzione per la funzione di confronto e passa una coppia di void * ' s.

Risposta

Come sottolineato da altre risposte, puoi utilizzare void* per strutture di dati generiche.Per altri tipi di polimorfismo parametrico, le macro del preprocessore venivano usate se qualcosa veniva ripetuto molto (come dozzine di volte). Ad essere onesti, tuttavia, la maggior parte delle volte per una ripetizione moderata, le persone hanno semplicemente copiato e incollato, quindi hanno cambiato i tipi, perché ci sono molte insidie con le macro che le rendono problematiche.

Abbiamo davvero bisogno di un nome per il contrario del blub paradosso , dove le persone hanno difficoltà a immaginare la programmazione in un linguaggio meno espressivo, perché questo viene fuori molto su questo sito. Se non hai mai usato un linguaggio con modi espressivi di implementare il polimorfismo parametrico, non sai veramente cosa ti stai perdendo. Accetti semplicemente che copiare e incollare sia alquanto fastidioso, ma necessario.

Ci sono inefficienze nelle tue attuali lingue di scelta di cui non sei nemmeno a conoscenza. Tra ventanni la gente si chiederà come li hai eliminati. La risposta breve è che non lo sapevi, perché non sapevi di poterlo fare.

Commenti

  • 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. Mi sembra esattamente un paradosso blub (" Le lingue meno potenti di Blub sono ovviamente meno potenti, perché ' re mancano alcune funzioni a cui ' era abituato. ") ' sarebbe lopposto se la persona conosceva i limiti della sua lingua ' e poteva immaginare caratteristiche che li risolvono.
  • Lopposto non è ' t abbastanza la parola che stavo cercando, ma ' è la più vicina che ho potuto trovare. Il paradosso blub presume la capacità di riconoscere un linguaggio meno potente, ma ' t commenta la difficoltà di comprendere la programmazione in uno. In modo un po controintuitivo, la capacità di programmare in un linguaggio più potente non ' conferisce unadeguata capacità di programmare in un linguaggio meno potente.
  • Sospetto " converse " è la parola che ' stai cercando: " Una situazione, un oggetto o unaffermazione che è il contrario di un altro o corrisponde ad esso ma con determinati termini trasposti "

Risposta

Ricordo quando gcc distribuì genclass – un programma che prendeva come input un insieme di tipi di parametri ( ad es. chiave e valore per una mappa) e un file di sintassi speciale che descrive un tipo parametrizzato (ad esempio, una mappa o un vettore) e ha generato unimplementazione C ++ valida con i tipi di parametro compilati.

Quindi se tu necessari Map<int, string> e Map<string, string> (questa non era la sintassi effettiva, tieni presente che) dovevi esegui quel programma due volte per generare qualcosa come map_string_string.he map_int_string.he poi usali nel tuo codice.

Vedi la pagina man per genclass e la documentazione dalla libreria GNU C ++ 2.0 per maggiori dettagli.

Risposta

[AllOP: “Non sto cercando di prendermi in giro personalmente, ma di aumentare la tua consapevolezza e quella degli altri” di pensare alla logica della domanda ( s) chiesto su SE e altrove. Per favore, non prenderla sul personale!]

Il titolo della domanda è buono, ma stai limitando gravemente la portata delle tue risposte includendo “… situazioni in cui era necessaria la generazione di codice in fase di compilazione. “In questa pagina esistono molte buone risposte alla domanda su come generare codice in fase di compilazione in C ++ senza modelli, ma per rispondere alla domanda che hai posto in origine:

Cosa facevano le persone prima dei modelli in C ++?

La risposta è, ovviamente, che loro (noi) non li usavamo. Sì, sono ironico, ma i dettagli della domanda nel corpo sembrano (forse esageratamente) presumere che tutti adorino i modelli e che nessuna codifica avrebbe mai potuto essere eseguita senza di essi.

Ad esempio, ho completato molti molti progetti di codifica in vari linguaggi senza la necessità di generare codice in fase di compilazione, e credo che anche altri lo abbiano fatto. Certo, il problema risolto dai modelli era un prurito abbastanza grande da essere effettivamente graffiato da qualcuno, ma lo scenario posto da questa domanda era, in gran parte, inesistente.

Considera una domanda simile nelle auto:

Come facevano i conducenti a passare da una marcia allaltra, utilizzando un metodo automatizzato che cambiava marcia per te, prima che fosse inventato il cambio automatico?

La domanda è, ovviamente, sciocca. Chiedere come una persona ha fatto X prima che X fosse inventato non è “veramente una domanda valida. La risposta è generalmente” non labbiamo fatto “e non ci siamo persi perché” non sapevamo che sarebbe mai esistito “.Sì, è facile vedere il vantaggio dopo il fatto, ma presumere che tutti fossero in piedi, a calci, in attesa della trasmissione automatica o dei modelli C ++, non è proprio vero.

Alla domanda “come facevano i guidatori a cambiare marcia prima che fosse inventato il cambio automatico?” Si può ragionevolmente rispondere “manualmente”, e questo è il tipo di risposte che si ottengono qui. Potrebbe anche essere il tipo di domanda che volevi fare.

Ma non era quella che hai fatto.

Quindi:

D: In che modo le persone utilizzavano i modelli prima che i modelli venissero inventati?

R: Non lo facevamo.

D: In che modo le persone utilizzavano i modelli prima che i modelli fossero inventati, quando avevano utilizzare modelli ?

R: Non avevamo bisogno di usarli. Perché supporre che lo abbiamo fatto? (Perché supporre che lo facciamo?)

D: Quali sono i modi alternativi per ottenere i risultati forniti dai modelli?

R: Esistono molte buone risposte sopra.

Per favore, pensa agli errori logici nei tuoi post prima di pubblicare.

[Grazie! Per favore, non è previsto alcun danno qui.]

Commenti

  • Penso che tu ' è eccessivamente pedante. LOP non ha formulato la sua domanda così bene come avrebbe potuto. Tuttavia penso che ' sia abbastanza chiaro che voleva chiedere qualcosa come " in che modo le persone creavano funzioni generiche prima modelli ". Penso che in questo caso lazione appropriata sarebbe stata quella di modificare la sua risposta o lasciare un commento piuttosto che tenere una conferenza piuttosto paternalistica.

Risposta

Lorribile macro è giusto, da http://www.artima.com/intv/modern2.html :

Bjarne Stroustrup: Sì. Quando dici “modello tipo T”, questo è davvero il vecchio matematico “per tutti i T.” Questo è il modo in cui viene considerato. Il mio primissimo articolo su “C con classi” (che si è evoluto in C ++) del 1981 menzionava i tipi parametrizzati. Ecco, ho risolto il problema, ma ho trovato la soluzione completamente sbagliata. Ho spiegato come puoi parametrizzare i tipi con le macro, e ragazzo questo era un codice scadente.

Puoi vedere come è stata utilizzata una vecchia versione macro di un modello qui : http://www.xvt.com/sites/default/files/docs/Pwr++_Reference/rw/docs/html/toolsref/rwgvector.html

Risposta

Come ha già detto Robert Harvey, un puntatore void è il tipo di dati generico.

Un esempio dalla libreria C standard, come ordinare un array di double con un ordinamento generico:

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

Dove compare_double è definito come:

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

La firma di qsort è definita in stdlib.h:

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

Tieni presente che non esiste un tipo controllo in fase di compilazione, nemmeno in fase di esecuzione. Se ordinate un elenco di stringhe con il comparatore sopra che prevede il doppio, tenterà felicemente di interpretare la rappresentazione binaria di una stringa come un doppio e di ordinare di conseguenza.

Risposta

Un modo per farlo è questo:

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

La macro DARRAY_TYPEDECL crea in modo efficace una definizione di struttura (in una singola riga), sostituendo name con il nome passato e memorizzando un array dei type passati (il name è lì in modo che tu possa concatenarlo al nome della struttura di base e hanno ancora un identificatore valido – darray_int * non è un nome valido per una struttura), mentre la macro DARRAY_IMPL definisce le funzioni che operano su quella struttura (in quel caso sono contrassegnate come statiche solo in modo che chiama la definizione solo una volta e non separa tutto).

Questo sarebbe usato come:

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

Risposta

Penso che i modelli vengano utilizzati molto come un modo per riutilizzare i tipi di contenitore che hanno un molti valori algoritmici come array dinamici (vettori), mappe, alberi, ecc., ordinamento, ecc.

Senza modelli, necessariamente, questi contengono implementazioni sono scritti in modo generico e vengono fornite solo informazioni sufficienti sul tipo richiesto per il loro dominio. Ad esempio, con un vettore, hanno solo bisogno che i dati siano “in grado” e hanno bisogno di conoscere la dimensione di ogni elemento.

Supponiamo che tu abbia una classe contenitore chiamata Vector che fa questo. Ci vuole void *. Lutilizzo semplicistico di questo sarebbe che il codice del livello dellapplicazione eseguisse un sacco di casting. Quindi, se gestiscono oggetti Cat, devono lanciare Cat * a void * e viceversa. Il codice dellapplicazione che si sporca con i cast presenta problemi evidenti.

I modelli risolvono questo problema.

Un altro modo per risolverlo è creare un tipo di contenitore personalizzato per il tipo che stai memorizzando nel contenitore. Quindi, se hai una classe Cat, devi creare una classe CatList derivata da Vector.Quindi sovraccarichi i pochi metodi che usi, introducendo versioni che accettano oggetti Cat invece di void *. Quindi “sovraccarichi il metodo Vector :: Add (void *) con Cat :: Add (Cat *), che internamente passa semplicemente il parametro a Vector :: Add (). Quindi nel codice dellapplicazione,” d richiama il versione sovraccarica di Add quando si passa in un oggetto Cat e quindi evitare il casting. Per essere onesti, il metodo Add non richiederebbe un cast perché un oggetto Cat * si converte in void * senza un cast. Ma il metodo per recuperare un elemento, come loverload dellindice o un metodo Get () lo farebbe.

Laltro approccio, lunico esempio del quale ricordo dai primi anni 90 con un framework applicativo di grandi dimensioni, è quello di utilizzare unutilità personalizzata che crea questi tipi sulle classi. Credo che MFC lo abbia fatto. Avevano classi diverse per i contenitori come CStringArray, CRectArray, CDoulbeArray, CIntArray, ecc. Piuttosto che mantenere un codice duplicato, hanno fatto un tipo di meta-programmazione simile alle macro, utilizzando uno strumento esterno che avrebbe generato le classi. Hanno reso lo strumento disponibile con Visual C ++ nel caso in cui qualcuno volevo usarlo – non lho mai fatto. Forse avrei dovuto. Ma a quel tempo, gli esperti reclamizzavano “Sane subset of C ++” e “You dont need Templates”

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *