Curiosità sulle variabili

di il
10 risposte

Curiosità sulle variabili

C' è un sistema per capire da programma la dimensione e magari anche il tipo di una variabile o di un vettore che è stato definito nel programma stesso?
vorrei realizzare una funzione con queste caratteristiche:
input nome variabile
output
1 campo numerico che mi indichi il tipo di variabile 0 per int ,1 per char etc etc
1 campo numerico che mi indichi se è una variabile o una matrice o un vettore 0 per variabile 1 per vettore 2 per matrice
1 campo numerico che mi dia la grandezza.
2 campi numerici che mi darebbero la dimensione della matrice eventualmente lo fosse.
senza usare file perchè rallenterebbe la procedura.
non ho la minima idea sul come fare.
ringrazio anticipatamente chiunque mi fornisca una idea sul come realizzare ciò.

10 Risposte

  • Re: Curiosità sulle variabili

    Se non è un puntatore, la dimensione la ricavi usando sizeof(nome_variabile) o sizeof(tipo_della_variabile).
    Per conoscere il tipo della variabile devi usare i type_traits.
    http://msdn.microsoft.com/en-us/library/bb982077.asp
    Un esempio minimale.
    Il tutto è valutato a compile time.
    
    #include <iostream>
    #include <type_traits>
    
    using namespace std;
    
    int main (int argc, char* argv[]) {
        
        cout << std::is_integer<int>::value << endl;
        cout << std::is_integer<double>::value << endl;
        cout << std::is_integer<int (&)[16]>::value << endl;
        
        cout << sizeof(int) << endl;
        char c;
        cout << std::is_pointer<decltype(c)>::value << endl;
        
    }
    
  • Re: Curiosità sulle variabili

    Scusa ma non ho capito bene come faccio a trarmi il tipo.
    non è che potresti farmi un piccolo esempio?
    che tu sappia posso fare
    int a
    a = std::is_integer<int>::value
    con vettori e matrici come posso fare ?
  • Re: Curiosità sulle variabili

    Sapere il tipo di una variabile ha senso solo nel contesto dei template. Negli altri casi o la sai già (visto che da qualche parte l'hai dichiarata), oppure in C++11 lo ricavi con il type inference usando decltype su una variabile già definita. La tua funzione pertanto deve essere un template con all'interno i vari traits che intendi usare per identificare ciò che passi.
    Ad esempio.
    
    template <typename T>
    struct which_type identify(T& var) {
        which_type mtype;
        memset(&type,0,sizeof(which_type));
        
        m_type.is_int = std::is_integer<T>::value;
    
        m_type.size = sizeof(T);
        m_type.is_float_or_double = std::is_floating_point<T>::value;
        // etc.
    }
    
    Vettori e matrici sono riconosciuti da questo modo di procedere solo se posti nello stack.
    Questo per quel che riguarda il compile time.
    Se hai bisogno di confronti runtime devi usare la RTTI del C++ che però non fornisce le informazioni che chiedi, ma permette di confrontare il tipo del dato passato a parametro con uno di riferimento.
    Tornando all'esempio di prima:
    
    template <typename T>
    struct which_type identify(T& var) {
        which_type mtype;
        memset(&type,0,sizeof(which_type));
        
        m_type.is_int = (typeid(var) == typeid(int));
    
        m_type.size = sizeof(T);
        m_type.is_float_or_double = (typeid(var) == typeid(float)) ||(typeid(var) == typeid(double)) ;
        // etc.
    }
    
    Per curiosità: a che ti serve sapere il tipo?
  • Re: Curiosità sulle variabili

    Sapere il tipo e molto utile perchè quando si creano funzioni generiche si possono controllare i campi di ingresso o si possono utilizzare per creare copie da utilizzare all'interno della procedura.
    senza avere campi che poi non verranno usati.
    esempio:
    int a;
    mia_funzione(parametri della funzione)
    preleva_tipo(a,int b) // in b ci vai il tipo
    adesso verifico il tipo e se il tipo mi serve allora creo una copia altrimenti restituisco un codice di errore.
    preleva_grandezza(a,int b)
    cosi potrei farmi una copia della variabile senza ne sovradimensionarla ne sottodimensionarla.
    // questo stratagemma è importante perchè per errore potrei passare come puntatore una variabile char al posto di una int o di una double.
  • Re: Curiosità sulle variabili

    questo stratagemma è importante perchè per errore potrei passare come puntatore una variabile char al posto di una int o di una double.
    Ed è il motivo per cui sono stati standardizzati i type_traits (ai quali si possono affiancare implementazioni proprie per i casi non ricoperti).
    Esempio pratico. Voglio che una funzione accetti solo puntatori a char.
    
    #include <type_traits>
    // Definisco un type_traits specifico per i char
    template <typename T>
    struct is_char : public std::false_type {}; // caso generico
    
    template <>
    struct is_char<char> : public std::true_type {}; // caso generico
    
    // voglio che questa funzione accetti solo char* o const char*
    template <typename T>
    void fx(T param) {
    
        // uso static assert per indurre un errore di compilazione se T non è un puntatore.
        // Se la condizione non è verificata, lo static_assert blocca la compilazione.
        static_assert(std::is_pointer<T>::value, "Errore: T non è un puntatore");
    
        // uso il mio traits is_char per verificare che il T sia di tipo char o const char
        static_assert( 
            is_char< 
                typename std::remove_cv<
                    typename std::remove_pointer<T>::type 
                >::type
           >value, "Errore: T non è un puntatore a char"
        );
    }
    
    int main(etc) {
    
        char c=0;
        char* pc =nullptr;
        const char* cpc = nullptr;
    
        fx(c);
        fx(pc);
        fx(cpc);
    }
    
    Se provi a eseguire il codice vedrai che finche non commenti fx(c), non riuscirai a compilare.
    Questo è l'unico sistema per non avere overhead a runtime.
  • Re: Curiosità sulle variabili

    Fantastico
    ma questo template,non li conoscevo, lo devo mettere in ogni programma o in ogni funzione?
  • Re: Curiosità sulle variabili

    I type_traits standard li trovi nel link che ti ho indicato, altrimenti occorre crearseli. Non che sia difficile capito il concetto, ma le prime volte bisogna stare attenti.
    Occorre ricordare che in presenza di template, il compilatore sceglie sempre quello più adatto, il più specializzato.
    Riprendendo is_char il tipo specializzato su char è appunto is_char<char> per cui nella funzione fx il compilatore si trova a dover scegliere tra il template generico is_char e quello specializzato is_char<char>. Per quanto detto sopra, il compilatore sceglierà is_char<char>. Se vuoi creare un type_traits specifico per un int, puoi seguire la falsariga di is_char, ma specializzato su int (is_int e is_int<int>) etc.

    static_assert() fa parte del C++11 che VC++10 implementa in parte.

    I controlli dipendono da cosa ti aspetti che sia il tipo T e in base a quello decidi il tipo di messaggio di errore. I miei traits (in un apposito namespace per evitare conflitti) li ho messi in un file di include che uso quando devo fare controlli simili a quelli che vuoi fare tu.
  • Re: Curiosità sulle variabili

    Grazie sembrano veramente utili.
    siccome non ho mai utilizzato i template
    ti faccio 2 domande
    1) c' é un sistema per immetterli nelle funzioni, senza dovermeli includere in ogni sorgente, che poi dovranno costituire una libreria?
    2) mica devo fare un template per ogni parametro della funzione?
    se si come posso verificare che una variabile non sia gia stata usata?
  • Re: Curiosità sulle variabili

    smalldragon ha scritto:


    grazie sembrano veramente utili.
    1) c' é un sistema per immetterli nelle funzioni, senza dovermeli includere in ogni sorgente, che poi dovranno costituire una libreria?
    No. I Template divergono dalle comuni funzioni perché il compilatore (inteso come compilatore + linker) non sa con che dato sta lavorando fintanto che non sono istanziati.
    In pratica non puoi avere la definizione di una funzione (o classe) template in un file .cpp: tutto deve stare nell'header file. Per di più la definizione va dichiarata inline.
    
    template <typename T>
    inline void fx(T qualcosa) {
       // fa qualcosa.
    }
    
    Va detto però che se un template non è istanziato, il compilatore lo ignora proprio.

    2) mica devo fare un template per ogni parametro della funzione?
    No, assolutamente.
    Ad esempio:
    
    template <typename T, typename U>
    inline void fx(T a, T b, U c, int len) {
       ...
    }
    
    In questo caso hai due tipi per due parametri diversi: T e U, sconosciuti fino a che userai la funzione; il terzo invece dev'essere per forza un int.
    In generale: se una funzione possiede anche solo un parametro template, allora è una funzione template.
  • Re: Curiosità sulle variabili

    Grazie quando mi arriverà il compilatore proverò sperando di non far casini.
Devi accedere o registrarti per scrivere nel forum
10 risposte