Visualizzazione dei risultati da 1 a 5 su 5
  1. #1

    C++ - restituire template di int, double o float etc.

    http://stackoverflow.com/questions/2...450157#2450157

    Sto cercando di capire in funzionamento di questo codice, che permetterebbe di restituire template con variabili int, float double etc. a seconda dei casi.

    Ho qualche domanda:

    1. che significato ha char[1] , indica un array?
    2. cosa fa l'operatore ternario '?:' ? Perché dovrebbe restituire una classe
    3. a che serve il size of?

    codice:
    // typedef eiher to A or B, depending on what integer is passed
    template<int, typename A, typename B>
    struct cond;
    
    #define CCASE(N, typed) \
      template<typename A, typename B> \
      struct cond<N, A, B> { \
        typedef typed type; \
      }
    
    CCASE(1, A); CCASE(2, B);
    CCASE(3, int); CCASE(4, unsigned int);
    CCASE(5, long); CCASE(6, unsigned long);
    CCASE(7, float); CCASE(8, double);
    CCASE(9, long double);
    
    #undef CCASE
    
    // for a better syntax...
    template<typename T> struct identity { typedef T type; };
    
    // different type => figure out common type
    template<typename A, typename B>
    struct promote {
    private:
      static A a;
      static B b;
    
      // in case A or B is a promoted arithmetic type, the template
      // will make it less preferred than the nontemplates below
      template<typename T>
      static identity<char[1]>::type &check(A, T);
      template<typename T>
      static identity<char[2]>::type &check(B, T);
    
      // "promoted arithmetic types"
      static identity<char[3]>::type &check(int, int);
      static identity<char[4]>::type &check(unsigned int, int);
      static identity<char[5]>::type &check(long, int);
      static identity<char[6]>::type &check(unsigned long, int);
      static identity<char[7]>::type &check(float, int);
      static identity<char[8]>::type &check(double, int);
      static identity<char[9]>::type &check(long double, int);
    
    public:
      typedef typename cond<sizeof check(0 ? a : b, 0), A, B>::type
        type;
    };
    
    // same type => finished
    template<typename A>
    struct promote<A, A> {
      typedef A type;
    };

    codice:
    che significato ha char[1] , indica un array?

  2. #2
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Quello che mi lascia perplesso è:
    codice:
     0 ? a : b
    in questa definizione:
    codice:
    typedef typename cond<sizeof check(0 ? a : b, 0), A, B>::type
    a rigor di logica, sia a compile time sia a run time il valore scelto sarà sempre b.
    Detto questo ti trovi davanti a meta programmazione template che non è semplice da capire.

    1) char[1] indica la dimensione di un array, non un classico array C (in questo caso: 1 appunto).

    2) L'operatore ternario (ammesso che qui serva), non restituisce una classe ma sceglie un parametro da passare a check (in apparenza sempre b).

    3) a fare quello che fa sempre: restituire una dimensione (di identity in questo caso).

    Dati due tipi A e B, dove A != B, il compilatore cerca una definizione di check compatibile con i tipi dati (in apparenza il solo B), sizeof restituisce la dimensione del tipo di ritorno (il char[n] corrispondente), e il tutto viene inoltrato a cond (o meglio a una sua specializzazione).
    In base alla specializzazione scelta dal compilatore si avrà la scelta del tipo di dato tra A e B (in apparenza almeno perché ci sono cose che mi lasciano un pò perplesso sul funzionamento, ma non ci metto la mano sul fuoco).
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  3. #3
    Originariamente inviato da shodan
    Quello che mi lascia perplesso è:
    codice:
     0 ? a : b
    in questa definizione:
    codice:
    typedef typename cond<sizeof check(0 ? a : b, 0), A, B>::type
    a rigor di logica, sia a compile time sia a run time il valore scelto sarà sempre b.
    Il valore non interessa, è un trucco per sfruttare l'algoritmo di scelta del tipo restituito dall'operatore ternario, descritto a [expr.cond] ¶3 dello standard.
    In base al tipo viene scelto l'appropriato overload di check, che a sua volta restituirebbe un array di dimensioni diverse a seconda dell'overload scelto. check in realtà non viene chiamato per davvero, dato che le espressioni dentro a sizeof non vengono valutate, ma se ne considera esclusivamente il tipo, e di fatto è tutto un trucco per ottenere il numero corrispondente a ciascun overload.
    Questo numero è quindi dato in pasto a cond, che è specializzato esplicitamente per tutti quei numeri (tramite la macro CCASE), e che include in sé nel membro type il tipo che gli è fatto corrispondere nella CCASE.
    Il trucco di identity credo sia necessario per forzare le funzioni a restituire un array di dimensioni fisse, cosa che normalmente credo non si potrebbe fare senza includerlo in una struct.
    Amaro C++, il gusto pieno dell'undefined behavior.

  4. #4
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Originariamente inviato da MItaly
    Il valore non interessa, è un trucco per sfruttare l'algoritmo di scelta del tipo restituito dall'operatore ternario, descritto a [expr.cond] ¶3 dello standard.
    Che il valore non interessasse l'avevo già notato, ma non sapevo come leggere quell'operatore ternario, ne che esistessero le clausole di conversione 2 e 3.
    La spiegazione però è da mal di testa.
    Il trucco di identity credo sia necessario per forzare le funzioni a restituire un array di dimensioni fisse, cosa che normalmente credo non si potrebbe fare senza includerlo in una struct.
    Non ne sono convinto, nel senso che una funzione di quel tipo potrebbe restituire la dimensione tramite un char[N] senza passare per uan struttura.
    In xstddef di VC++2010 Expr. esiste la dichiarazione:
    codice:
    typedef char (&_No)[1];
    typedef char (&_Yes)[2];
    e diverse funzioni (per la SFINAE) restituiscono _No o _Yes senza passare per una struttura.
    A conti fatti, comunque, il risultato è lo stesso.
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  5. #5
    Originariamente inviato da shodan
    Che il valore non interessasse l'avevo già notato, ma non sapevo come leggere quell'operatore ternario, ne che esistessero le clausole di conversione 2 e 3.
    La spiegazione però è da mal di testa.
    Fa parte di quei paragrafi dello standard che sono abbastanza illeggibili, un altro che raccomando è quello sulle regole complete di risoluzione dell'overloading, tra regole "normali", conversioni automatiche e ADL c'è da spararsi.

    Non ne sono convinto, nel senso che una funzione di quel tipo potrebbe restituire la dimensione tramite un char[N] senza passare per uan struttura.
    In xstddef di VC++2010 Expr. esiste la dichiarazione:
    codice:
    typedef char (&_No)[1];
    typedef char (&_Yes)[2];
    e diverse funzioni (per la SFINAE) restituiscono _No o _Yes senza passare per una struttura.
    A conti fatti, comunque, il risultato è lo stesso.
    Forse molto banalmente l'autore di quel codice non ci ha pensato. Oppure voleva aggiungere un po' di template in più per il gusto di farlo.
    Amaro C++, il gusto pieno dell'undefined behavior.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.