Sono dei Template C++ solo Macro sotto mentite spoglie?

Ho avuto la programmazione in C++ per un paio di anni, e ho usato STL da un po ‘ e hanno creato il mio template di classi un paio di volte per vedere come è fatto.

Ora sto cercando di integrare i modelli più profondo nella mia OO design e un pensiero fastidioso continua a tornare per me: Sono proprio una macro, davvero… Si potrebbe implementare (piuttosto BRUTTO) auto_ptrs utilizzando #definisce, se si voleva davvero.

Questo modo di pensare modelli mi aiuta a capire come il mio codice in realtà funziona, ma sento che mi manca il punto in qualche modo. Le macro sono pensati male incarnato, ma “template metaprogramming” è la rabbia.

Quindi, quali SONO i reali distinzioni? e come modelli di evitare i pericoli che #define ci porta dentro, come

  • Imperscrutabile errori del compilatore in
    luoghi in cui non vi aspettate di loro?
  • Codice bloat?
  • Difficoltà a rintracciare il codice?
  • Impostazione Debugger Punti Di Interruzione?
  • Perché credi che il “template metaprogramming è la rabbia”?
  • No, non sono. 🙂 E la tua domanda è molto caricato, perché i modelli di aiutare con nessuno dei problemi che hai menzionato. Invece di una intera classe di problemi si può comodamente ignorare. La domanda presuppone una risposta, e se mi fosse mi sarebbe di una mente, di squalificare per essere soggettiva e argumentitive.
  • era un commento a questa questione, o quella che ha unito con la mia? Questo polverone più di un anno-morti domanda è: facendo la mia testa…
  • Template metaprogramming è fantastica (la rabbia) — almeno la vedo un’area portatili di programmazione a basso livello. Persone sono state utilizzando per il preprocessore(livello 1) meta-programmazione, dal momento che il token di concatenazione in ANSI-C, il potenziale è infinito con C++meccanismo di template — è tutta la rabbia; tuttavia, ci sono pochi strumenti, e che mette un ammortizzatore sulle cose.
InformationsquelleAutor Roddy | 2008-10-07



25 Replies
  1. 50

    Macro sono un testo meccanismo di sostituzione.

    Modelli sono funzionali linguaggio turing-completo eseguito a tempo di compilazione e integrato con il C++ tipo di sistema. Si può pensare a loro come un plugin meccanismo per la lingua.

  2. 30

    C’è un sacco di commenti, qui, cercando di differenziare le macro e modelli.

    Sì – sono entrambe la stessa cosa: la generazione del Codice di strumenti.

    Macro sono una forma primitiva, senza molto compilatore di esecuzione (come fare Oggetti in C – può essere fatto, ma non abbastanza). I modelli più avanzati, e sono molto meglio compilatore tipo di controllo, i messaggi di errore, ecc.

    Tuttavia, ognuno ha punti di forza che l’altro non.

    Modelli possono solo generare classe dinamica tipi di macro in grado di generare quasi qualsiasi codice che si desidera (che non sia un altro definizione di macro). Le macro possono essere molto utile per inserire tabelle statiche di dati strutturati in codice.

    Modelli invece possono realizzare alcune veramente FUNKY cose che non sono possibili con le macro. Per esempio:

    template<int d,int t> class Unit
    {
        double value;
    public:
        Unit(double n)
        {
            value = n;
        }
        Unit<d,t> operator+(Unit<d,t> n)
        {
            return Unit<d,t>(value + n.value);
        }
        Unit<d,t> operator-(Unit<d,t> n)
        {
            return Unit<d,t>(value - n.value);
        }
        Unit<d,t> operator*(double n)
        {
            return Unit<d,t>(value * n);
        }
        Unit<d,t> operator/(double n)
        {
            return Unit<d,t>(value / n);
        }
        Unit<d+d2,t+t2> operator*(Unit<d2,t2> n)
        {
            return Unit<d+d2,t+t2>(value + n.value);
        }
        Unit<d-d2,t-t2> operator/(Unit<d2,t2> n)
        {
            return Unit<d-d2,t-t2>(value + n.value);
        }
        etc....
    };
    
    #define Distance Unit<1,0>
    #define Time     Unit<0,1>
    #define Second   Time(1.0)
    #define Meter    Distance(1.0)
    
    void foo()
    {
       Distance moved1 = 5 * Meter;
       Distance moved2 = 10 * Meter;
       Time time1 = 10 * Second;
       Time time2 = 20 * Second;
       if ((moved1 / time1) == (moved2 / time2))
           printf("Same speed!");
    }

    Il modello consente al compilatore di creare in modo dinamico e tipo di uso-sicuro le istanze del modello on-the-fly. Il compilatore esegue effettivamente il modello-parametro di matematica in fase di compilazione, la creazione di classi separate, ove necessario, per ogni risultato unico. C’è un’implicita Unit<1,-1> (distanza /tempo = velocità) tipo che viene creato e rispetto all’interno del condizionale, ma mai esplicitamente dichiarato nel codice.

    A quanto pare, qualcuno all’università ha definito un modello di questo tipo con 40+ parametri (è bisogno di un riferimento), ognuno dei quali rappresenta un diverso fisica tipo di unità. Pensate al tipo di sicurezza di questo tipo di classe, solo per i numeri.

    • Ho avuto qualche idea di che cosa stavano cercando di fare fino a quando ho avuto modo di “Unit<p+d2,t+t2>”, quando ho perso la trama. Si può spiegare ciò che sta cercando di fare e che vantaggi dà più “typedef double Distanza”/”typedef double Time”, che sembra dare lo stesso risultato?
    • Dichiarare due variabili: d è la Distanza, il Tempo t; Se la Distanza e il Tempo sono entrambe le camere, la dichiarazione (d = t) e l’espressione (d == t) sono entrambi validi. Il modello lo impedisce: – fornire il tipo di sicurezza per i valori numerici.
    • Ah! Grazie. Non sarei MAI stato in grado di dedurre che per me!
    • per ‘Dedurre che’
    • “Macro può essere molto utile per inserire tabelle statiche di dati strutturati in codice.” — che non è una delle cose che i modelli non possono fare. 😉 Ci sono cose che i modelli non possono fare, ma sono soprattutto reificazione; la creazione di nuovi token, ecc.
  3. 29

    Sono analizzate dal compilatore e non da un preprocessore che corre prima il compilatore.

    Ecco cosa MSDN dice a questo proposito:
    http://msdn.microsoft.com/en-us/library/aa903548(VS.71).aspx

    Qui ci sono alcuni problemi con le macro:

    • Non vi è alcun modo per il compilatore per verificare che i parametri macro sono di compatibili.
    • La macro è espansa senza alcun tipo di controllo.
    • La i e la j parametri vengono valutati due volte. Per esempio, se il parametro ha un postincremented variabile, l’incremento viene eseguita due volte.
    • Perché le macro sono espansi per il preprocessore, messaggi di errore del compilatore farà riferimento all’aumento del numero di macro, piuttosto che la definizione della macro stessa. Inoltre, la macro si mostra in forma estesa durante il debug.

    Se questo non è abbastanza per voi, non so che cosa è.

    • MSDN link utilizza un modello per Min, che è praticamente il finale “cattivo esempio”. Vedere Scott Meyer di carta sui modelli per Min/Max. aristeia.com/Papers/C++ReportColumns/jan95.pdf
    • Ovviamente sei tecnicamente giusto, ma dire che uno è trasformati tramite il preprocessore e l’altro per il compilatore non dà una ragione sul perché uno è meglio dell’altro.
    • Sei stato sleale. Min come modello è abbastanza semplice da comprendere nel suo stato imperfetto e offre una migliore protezione rispetto alle macro. Alexandrescu ha una soluzione per il min/max problema, ma è abbastanza complesso, troppo complesso per i miei gusti.
    • Bene… per questo sto citando MSDN. Sono abbastanza esplicito: tipo di controllo, fare doppio incremento di protezione, i messaggi di errore. Essi , provengono dal fatto che si tratta di elaborati entro il compilatore, è non farlo nel preprocessore. Chi se ne frega di modelli di essere un linguaggio Turing-completo ?
    • Sì, Min è semplice da capire, ma è anche non è UTILE, per le ragioni sono intesi da SM. Come dice lui “Il gallo di tutto questo è che stiamo parlando della funzione max qui! Come può un concettualmente semplice funzione di causare così tanti problemi?”
    • Tutti che Scott Meyer articolo non rendono in pieno il senso. Se si desidera ottenere un riferimento, di ritorno da una funzione min() quindi entrambi gli argomenti devono essere dello stesso tipo (e modificatore const) fortemente il tipo di linguaggio come il C++, dato che, per definizione, non si conosce al momento della compilazione, che dell’argomento di riferimento sta per essere restituito. Mi sembra di aver cercato di risolvere un problema artificiale creato per amore di discussione.

  4. 22

    La risposta è così a lungo, non posso riassumere tutto, ma:

    • per esempio le macro non garantire la sicurezza del tipo, mentre la funzione di modelli di fare: non c’è modo per il compilatore per verificare che i parametri macro sono di tipi compatibili — inoltre al momento il modello di funzione viene creata un’istanza che il compilatore sa se int o float definire operator +
    • modelli di aprire la porta per metaprogrammazione (in breve, di valutare le cose e prendere una decisione al momento della compilazione): in fase di compilazione, è possibile sapere se un tipo è integrale o in virgola mobile; se si tratta di un puntatore o se si tratta di const qualificato, ecc… vedere “tipo di tratti” nei prossimi c++0x
    • modelli di classe hanno la specializzazione parziale
    • funzione di modelli espliciti pieno di specializzazione, nel tuo esempio add<float>(5, 3); potrebbe essere implementato in modo diverso rispetto add<int>(5, 3); che non è possibile con le macro
    • macro non ha scopo
    • #define min(i, j) (((i) < (j)) ? (i) : (j)) – il i e j parametri vengono valutati due volte. Per esempio, se il parametro ha un postincremented variabile, l’incremento viene eseguita due volte
    • perché le macro sono espansi per il preprocessore, messaggi di errore del compilatore farà riferimento all’aumento del numero di macro, piuttosto che la definizione della macro stessa. Inoltre, la macro si mostra in forma estesa durante il debug
    • ecc…

    Nota: In alcuni rari casi, ho preferito fare affidamento su variadic macro in quanto non vi è alcuna cosa come variadic modelli fino al c++0x diventa mainstream. C++11 è vivo.

    Riferimenti:

    • Abbiamo un arrabbiato downvoter qui 😉 anche io non hanno idea di che cosa sto downvoted per 😉
    • Si sono probabilmente ottenere negged da un altro respondant chi vuole il suo/la sua risposta, per arrivare al top della lista di prima, dove è più probabile che per ottenere contrassegnato come accettato di rispondere.
    • perché crede che la sua incapacità di porre una domanda è una ragione sufficiente per colpa di tutti, che non ha dato la risposta che voleva. Io sono quasi tentato di downvote la questione, ma ciò di cui ho bisogno è un modo per downvote persona 😉
    • Ora che le domande sono stati uniti, mi sento stupido, i miei commenti sembrano accusare il poster con quello che lui non ha mai fatto 😉
    • Per favore qualcuno può spiegare perché il mio anno-vecchia questione è all’improvviso tintinnio di tutti gabbie? Penso che devo perdere la trama qui…
    • Oh, e Gregorio, +1 per la risposta utile con un po ‘ di punti.
    • a quanto pare si è fusa una nuova domanda con quello vecchio 🙂
    • thx che spiega molte cose. [E no, io non sono un fantasma downvoter. Cose migliori da fare con il mio tempo!]
    • sto cancellare i miei commenti, io non voglio essere la destinazione
    • c++0x ora c++11 … Ma io non downvote per quella 😉
    • un rapido cercare il pelo nell’uovo…macro non hanno portata, ma la loro portata (in C macro language) è esplicito. è possibile #undef loro di porre fine alla loro portata.

  5. 12

    Su un livello molto di base, sì, del modello sono solo di macro sostituzioni. Ma stai saltando su un sacco di cose da pensare in questo modo.

    Considerare il modello di specializzazione, che, a mia conoscenza, non è possibile simulare con macro. Non solo che permettano di, bene, implementazione speciale per determinati tipi di, è uno dei punti chiave del modello di meta-programmazione:

    template <typename T>
    struct is_void
    {
        static const bool value = false;
    }
    
    template <>
    struct is_void<void>
    {
        static const bool value = true;
    }

    Che, di per sé, è solo un esempio di molte cose si possono fare. I modelli stessi sono Turing-completo.

    Che ignora le cose molto basilari, come il campo di applicazione, il tipo di sicurezza, e che le macro sono messier.

  6. 10

    NON. Un semplice esempio di contatore: modelli a rispettare gli spazi dei nomi, macro ignorare gli spazi dei nomi (come sono preprocessore dichiarazioni).

    namespace foo {
        template <class NumberType>
        NumberType add(NumberType a, NumberType b)
        {
            return a+b;
        }
    
        #define ADD(x, y) ((x)+(y))
    } //namespace foo
    
    namespace logspace 
    {
        //no problemo
        template <class NumberType>
        NumberType add(NumberType a, NumberType b)
        {
            return log(a)+log(b);
        }
    
        //redefintion: warning/error/bugs!
        #define ADD(x, y) (log(x)+log(y))
    
    } //namespace logspace
  7. 9

    Template C++ sono un po ‘ come il Lisp macro (non C macro) che operano sul già analizzato versione del codice e che permette di generare codice arbitrario in fase di compilazione. Purtroppo, la programmazione in qualcosa di simile al raw del Lambda calcolo, in modo da tecniche avanzate, come il looping è una specie di ingombranti. Per tutti i dettagli scabrosi, vedere Generativa di Programmazione da Krysztof Czarnecki e Ulrich Eisenecker.

  8. 6

    Nel caso In cui siete alla ricerca di una trattazione approfondita dell’argomento, io posso girare a tutti C++ preferito hater. Quest’uomo conosce e che odia di più C++ di quanto io possa mai sognare di. Questo, contemporaneamente, rende account completi incredibilmente infiammatorie e una risorsa eccellente.

    • Tranne che quando guardo l’account completi capisco che davvero non sa di cosa sta parlando. Molte delle sue lamentele sono dovute ad abuso di C++.
  9. 5
    • modelli sono tipizzate.
    • basato su modelli di oggetti /tipi di namespace, fatti privati, i membri di una classe, etc.
    • parametri per funzioni basato su modelli non sono replicati in tutto il corpo della funzione.

    Queste sono davvero un grosso problema e prevenire una moltitudine di bug.

  10. 4

    Qualcosa che non è stato menzionato è che i modelli di funzioni in grado di dedurre i tipi di parametro.

    modello <typename T> 
    void func(T t) 
    { 
    T make_another = t; 
    

    Si può sostenere che la prossima “typeof” operatore in grado di risolvere, ma anche non può suddividere altri modelli:

    modello <typename T> 
    void func(contenitore<T> c) 
    

    o anche:

    modello <tempate <typename> classe Contenitore, typename T> 
    void func(Contenitore<T> ct) 
    

    Ho anche la sensazione che il soggetto di specializzazione non è stato coperto abbastanza. Ecco un semplice esempio di ciò che le macro non si può fare:

    modello <typename T> 
    T min(T a, T B) 
    { 
    ritorno a < b ? a : b; 
    } 
    
    modello <> 
    char* min(char* a, char* b) 
    { 
    if (strcmp(a, b) < 0) 
    ritorno a; 
    altro 
    return b; 
    } 
    

    Lo spazio è troppo piccolo per andare in tipo di specializzazione, ma quello che si può fare con esso, per quanto mi riguarda, è la mente che soffia.

  11. 4

    No, non è possibile. Il preprocessore è (appena) sufficiente per un paio di cose come contenitori di T, ma è semplicemente insufficiente per un bel paio di altre cose di modelli in grado di fare.

    Per alcuni esempi reali, leggere Moderna di Programmazione C++, da Andre Alexandrescu, o C++ Metaprogrammazione da Dave Abrahams e Aleksey Gurtovoy. Quasi nulla di fatto, in entrambi i libro può essere simulato per più di un estremamente minimale di laurea con il preprocessore.

    Edit: per Quanto riguarda typename va, il requisito è abbastanza semplice. Il compilatore non può sempre capire se un dipendente nome si riferisce ad un tipo o no. Utilizzando typename esplicitamente indica al compilatore che si riferisce ad un tipo.

    struct X { 
        int x;
    };
    
    struct Y {
        typedef long x;
    };
    
    template <class T>
    class Z { 
        T::x;
    };
    
    Z<X>; //T::x == the int variable named x
    Z<Y>; //T::x == a typedef for the type 'long'

    typename dice al compilatore che un particolare nome è destinato a fare riferimento a un tipo, non una variabile/valore, quindi (per esempio) è possibile definire altre variabili di quel tipo.

  12. 4

    Questa risposta è destinato a far luce sulla preprocessore C e come può essere utilizzato per la programmazione generica


    Sono in qualche materia, che consentono di simile semantica. Il preprocessore C è stato utilizzato per attivare generico algoritmi e strutture di dati (Vedere token Concatination). Tuttavia, senza considerare tutte le altre caratteristiche del template C++, fa tutta la programmazione generica gioco un MOLTO più CHIARA di leggere e mettere in pratica.

    Se qualcuno vuole vedere hardcore C solo la programmazione generica in azione leggi il libevent sourcecode — questo è anche citato qui. Una vasta collezione di contenitore/algoritmi implementati, ed è tutto fatto in SINGOLO file di intestazione (molto leggibile). Ammiro molto questo, C++ codice del modello (e che io preferisco per i suoi altri attributi) è MOLTO dettagliato.

  13. 2

    Modelli sono di tipo sicuro. Con la definisce, è possibile avere il codice che compila, ma continua a non funzionare correttamente.

    Macro espandere prima compilatore ottiene il codice. Questo significa che si potrebbe ottenere un messaggio di errore per esteso il codice, e debugger vede solo la versione estesa.

    Con le macro, c’è sempre la possibilità che una certa espressione è valutata due volte. Immaginare il passaggio di qualcosa di simile a ++x come parametro.

  14. 2

    Modelli possono essere messi in spazi dei nomi, o essere membri di una classe. Le macro sono solo una pre-fase di lavorazione. In sostanza, i modelli sono un primo membro della classe di lingua che suona bello (bello?) con tutto il resto.

  15. 2

    Modelli può fare molto di più che la macro del preprocessore è in grado di fare.

    E. g. ci sono template specializzazioni: Se questo modello è istanziati con questo tipo o costante, di non utilizzare l’implementazione di default, ma questo qui…

    … i modelli possono imporre l’applicazione di alcuni parametri che sono dello stesso tipo, ecc…


    Qui ci sono alcune fonti che Si potrebbe desiderare di guardare:

    • Template C++ da Vandervoorde e Jossutis. Questo è il migliore e più completo libro su modelli di so.
    • La libreria boost consiste quasi interamente di definizioni di modello.
  16. 2

    Anche se i parametri del modello sono di tipo controllato e ci sono molti vantaggi di modelli oltre le macro, i modelli sono molto simili macro, che sono ancora basate su testo di sostituzione. Il compilatore non verificare che il codice del modello e ha un senso fino a quando si dà parametri di tipo sostitutivo. Per esempio, Visual C++ non si lamenta di questa funzione in realtà non si chiamano:

    template<class T>
    void Garbage(int a, int b)
    {
        fdsa uiofew & (a9 s) fdsahj += *! wtf;
    }

    Di conseguenza, è, in generale, è impossibile sapere se il codice del modello e funziona correttamente, o compilare con successo, per una determinata categoria di parametri di tipo che il modello è stato progettato per accettare.

    • Si compila solo quella funzione, se ne ha bisogno. Che è il motivo per cui non dà alcun errore.
  17. 2

    A mio parere, le macro sono una cattiva abitudine da C. anche se può essere utile per alcuni non vedo una reale necessità per loro quando ci sono tipi e modelli. I modelli sono la naturale continuazione della Programmazione Orientata agli Oggetti. Si può fare molto di più con i modelli…

    Considerare questo…

    int main()
    {
        SimpleList<short> lstA;
        //...
        SimpleList<int> lstB = lstA; //would normally give an error after trying to compile
    }

    Per effettuare la conversione, è possibile utilizzare qualcosa che è definito un costruttore di conversione e una sequenza costruttore (vedi alla fine) lungo il più completo esempio di lista:

    #include <algorithm>
    
    template<class T>
    class SimpleList
    {
    public:
        typedef T value_type;
        typedef std::size_t size_type;
    
    private:
        struct Knot
        {
            value_type val_;
            Knot * next_;
            Knot(const value_type &val)
            :val_(val), next_(0)
            {}
        };
        Knot * head_;
        size_type nelems_;
    
    public:
        //Default constructor
        SimpleList() throw()
        :head_(0), nelems_(0)
        {}
        bool empty() const throw()
        { return size() == 0; }
        size_type size() const throw()
        { return nelems_; }
    
    private:
        Knot * last() throw() //could be done better
        {
            if(empty()) return 0;
            Knot *p = head_;
            while (p->next_)
                p = p->next_;
            return p;
        }
    
    public:
        void push_back(const value_type & val)
        {
            Knot *p = last();
            if(!p)
                head_ = new Knot(val);
            else
                p->next_ = new Knot(val);
            ++nelems_;
        }
        void clear() throw()
        {
            while(head_)
            {
                Knot *p = head_->next_;
                delete head_;
                head_ = p;
            }
            nelems_ = 0;
        }
        //Destructor:
        ~SimpleList() throw()
        { clear(); }
        //Iterators:
        class iterator
        {
            Knot * cur_;
        public:
            iterator(Knot *p) throw()
            :cur_(p)
            {}
            bool operator==(const iterator & iter)const throw()
            { return cur_ == iter.cur_; }
            bool operator!=(const iterator & iter)const throw()
            { return !(*this == iter); }
            iterator & operator++()
            {
                cur_ = cur_->next_;
                return *this;
            }
            iterator operator++(int)
            {
                iterator temp(*this);
                operator++();
                return temp;
            }
            value_type & operator*()throw()
            { return cur_->val_; }
            value_type operator*() const
            { return cur_->val_; }
            value_type operator->()
            { return cur_->val_; }
            const value_type operator->() const
            { return cur_->val_; }
        };
        iterator begin() throw()
        { return iterator(head_); }
        iterator begin() const throw()
        { return iterator(head_); }
        iterator end() throw()
        { return iterator(0); }
        iterator end() const throw()
        { return iterator(0); }
        //Copy constructor:
        SimpleList(const SimpleList & lst)
        :head_(0), nelems_(0)
        {
            for(iterator i = lst.begin(); i != lst.end(); ++i)
                push_back(*i);
        }
        void swap(SimpleList & lst) throw()
        {
            std::swap(head_, lst.head_);
            std::swap(nelems_, lst.nelems_);
        }
        SimpleList & operator=(const SimpleList & lst)
        {
            SimpleList(lst).swap(*this);
            return *this;
        }
        //Conversion constructor
        template<class U>
        SimpleList(const SimpleList<U> &lst)
        :head_(0), nelems_(0)
        {
            for(typename SimpleList<U>::iterator iter = lst.begin(); iter != lst.end(); ++iter)
                push_back(*iter);
        }
        template<class U>
        SimpleList & operator=(const SimpleList<U> &lst)
        {
            SimpleList(lst).swap(*this);
            return *this;
        }
        //Sequence constructor:
        template<class Iter>
        SimpleList(Iter first, Iter last)
        :head_(0), nelems_(0)
        {
            for(;first!=last; ++first)
                push_back(*first);
    
    
        }
    };

    Guardare il informazioni cplusplus.com sui modelli! È possibile utilizzare i modelli per fare quello che viene chiamato tratti che viene utilizzato è una sorta di documentazione per i tipi e così via. Si può fare molto di più con i modelli poi ciò che è possibile con le macro!

  18. 2

    Typename parola chiave è presentata per consentire contesto di nidificati typdef s. Questi sono stati necessari per la caratteristica tecnica che permettono di meta-dati per essere aggiunti ai tipi (soprattutto built-in tipi come un puntatore), questo è stato richiesto di scrivere il STL. La parola chiave typename altrimenti è la stessa come la parola chiave class.

  19. 2

    Proviamo primitiva esempio. Considerare

    #define min(a,b) ((a)<(b))?(a):(b)

    invocato come

    c = min(a++,++b);

    Naturalmente, la vera differenza è profonda, ma che dovrebbe essere sufficiente per eliminare analogie con il macro.

    Modifica: E no, non è possibile garantire la sicurezza di tipo macro. Come implementare typesafe min() per ogni tipo di definizione meno di confronto (cioè operrator<)?

    • Leggi le mie risposte alle risposte, che non è la risposta che sto cercando.
    • mentre la macro come scritto fa qualcosa di inaspettato, potrebbe essere scritto in modo da valutare gli argomenti solo una volta. (non downvote)
    • Ehm… È questo il motivo per cui downvote?
    • solo uno, mi viene il dubbio che potrebbe. E anche se potesse, si può venire con la migliore esempio quindi utilizzando la stessa idea.
    • qualcuno: Ok, scrivere un min(a, b) macro che non doppio valutare un argomento, e non solo potrete stabilire il tuo punto, ma mi impressiona molto. Non credo che si può fare.
    • Ora che le risposte sono migrati a questa domanda non hanno l’aspetto di vere risposte 😉
    • Non ho il tempo per scrivere ora, ma lo chiedi, vedrai 🙂

  20. 2

    Modelli capire i tipi di dati. Le macro non.

    Questo significa che si può fare roba come la seguente…

    • Definire un’operazione (ad esempio, uno per avvolgere i numeri) che può assumere qualsiasi tipo di dati, quindi fornire le specializzazioni che scegliere l’algoritmo appropriato in base a se il tipo di dati è integrale o in virgola mobile
    • Determinare gli aspetti della vostra tipi di dati in fase di compilazione, permettendo trucchi come modello deduzione della dimensione della matrice, che Microsoft utilizza per il C++ sovraccarichi di strcpy_s e il suo ilk

    Inoltre, poiché i modelli sono di tipo sicuro, ci sono un numero di modello di tecniche di codifica che potrebbero essere eseguite con qualche ipotetica avanzata del preprocessore, ma sarebbe difettose e soggetto a errori al meglio (ad esempio, modello parametri del modello, modello predefinito argomenti, politica di modelli come discusso in C++ Moderno Design).

  21. 2

    Modelli sono solo simili per le macro la funzionalità di base. Dopo tutto, i modelli sono stati introdotti in lingua “civilizzato” alternativa per le macro. Ma anche quando si tratta di che la maggior parte delle funzionalità di base, la somiglianza è solo la pelle in profondità.

    Tuttavia, una volta che si arriva a funzionalità più avanzate di modelli, come la specializzazione (parziale o esplicita) di qualsiasi apparente somiglianza con le macro scompare del tutto.

  22. 1

    Questa non è una risposta così tanto come conseguenza delle risposte già detto.

    In collaborazione con gli scienziati, i medici, artisti grafici e altri che hanno bisogno di program – ma non sono e non saranno mai professionale a tempo pieno, gli sviluppatori di software – vedo che le macro sono facilmente comprensibili dal programmatore amatoriale, mentre i modelli sembrano richiedono un livello superiore di pensiero astratto possibile solo con un profondo e costante esperienza di programmazione in C++. Ci vogliono molti casi di lavoro con il codice dove i modelli sono utili concetto, il concetto di dare un senso a sufficienza per l’uso. Mentre che potrebbe essere detto di ogni caratteristica del linguaggio, la quantità di esperienza per i modelli presenta un divario più ampio di quanto lo specialista casual programmatore è probabile che per guadagnare dal loro lavoro quotidiano.

    Media astronomo e ingegnere elettronico probabilmente groks macro bene, può anche capire perché macro dovrebbe essere evitato, ma non grok modelli abbastanza bene per l’uso quotidiano. In tale contesto, le macro sono in realtà meglio. Naturalmente, esistono molte tasche delle eccezioni; in alcuni fisici eseguire cerchi intorno alla pro ingegneri del software, ma questo non è tipico.

  23. 1

    Ci sono alcuni problemi di base con le macro.

    Prima, che non rispettano l’ambito o il tipo. Se ho #define max(a, b)..., quindi ogni volta che ho il token max nel mio programma, per qualsiasi ragione, non sarà sostituito. Sarà sostituito se è un nome di variabile o in profondità all’interno nidificati ambiti. Questo può causare difficili da trovare per gli errori di compilazione. Al contrario, i modelli di lavoro all’interno del C++ tipo di sistema. Un modello di funzione può avere il suo nome riutilizzato all’interno di un ambito e non provare a riscrivere il nome di una variabile.

    Secondo, le macro non può essere variata. Il modello std::swap normalmente dichiarare una variabile temporanea e fare l’ovvio assegnazioni, perché è il modo più ovvio che normalmente funziona. Che è quello che una macro dovrebbe essere limitato. Sarebbe estremamente inefficiente per i grandi vettori vettori hanno una speciale swap che riporti i riferimenti piuttosto che l’intero contenuto. (Questo risulta essere molto importante in roba medio programmatore C++ non dovrebbe scrivere, ma non l’uso.)

    Terzo, macro, non può fare a qualsiasi forma di tipo di interferenza. Non è possibile scrivere un generico swap macro, in primo luogo, perché sarebbe necessario dichiarare una variabile di un tipo, e non sa che il tipo non poteva essere. I modelli sono di tipo a conoscenza.

    Un grande esempio del potere di modelli è ciò che è stato originariamente chiamato la Standard Template Library, che è la standard dei contenitori e algoritmi e iteratori. Date un’occhiata a come funzionano, e cercare di pensare come vuoi sostituirlo con le macro. Alexander Stepanov guardato su una grande varietà di lingue per attuare il suo STL idee, e ha concluso che il C++ con modelli è stato l’unico a lavorare in.

  24. 0

    Modelli di offrire un certo grado di sicurezza del tipo.

    • che è come dire “funzioni di offrire un certo grado di sicurezza del tipo sopra macro’. mentre è tecnicamente vero, non è tutta la risposta, e certamente non prescrittivo.

Lascia un commento