Come ottengo il tipo di una variabile?


130

In C ++, come si trova il tipo di una variabile?



7
cout << typeid (variabile) .name () << endl;
SRN

2
Usate la ricerca o google :) stackoverflow.com/questions/81870/print-variable-type-in-c Theharshest è veloce: D
Kariboo

14
@Kariboo, ho usato Google e mi ha mandato qui.
Michael Warner

Questa domanda è molto poco chiara così com'è, e anche dopo aver visto le varie risposte; non è affatto chiaro che la domanda cerchi la risposta accettata.
Antti Haapala,

Risposte:


158

Puoi usare l'operatore typeid :

#include <typeinfo>
...
cout << typeid(variable).name() << endl;

15
@David - Quindi isignifica numero intero sul tuo compilatore. I nomi restituiti non sono specificati dallo standard.
Bo Persson

11
Quando lo uso su vector <int> restituisce St6vectorIiSaIiEE. WTF?
Boyan Kushlev,


5
I nomi restituiti da typeidsono molto abbreviati, specifici del compilatore e non destinati al consumo umano. Puoi "smangiarli" (questo è il termine effettivo!), Sia in codice con qualcosa come gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html , con utilità a riga di comando come c++filt, o con uno qualsiasi dei vari demanglers online come demangler.com .
cincodenada

33

Per le asserzioni statiche, è stato introdotto C ++ 11, decltypeche è abbastanza utile in determinati scenari.


12

Se hai una variabile

int k;

Puoi ottenere il suo tipo usando

cout << typeid(k).name() << endl;

Vedi il seguente thread su SO: Domanda simile


9

La principale differenza tra C ++ e Javascript è che C ++ è un linguaggio di tipo statico, mentre javascript è dinamico.

Nei linguaggi tipizzati dinamici una variabile può contenere qualsiasi cosa, e il suo tipo è dato dal valore che detiene, momento per momento. Nei linguaggi di tipo statico il tipo di una variabile è dichiarato e non può cambiare.

Possono esserci invio dinamico e composizione di oggetti e sottotipizzazione (ereditarietà e funzioni virtuali), invio statico e supertyping (tramite template CRTP), ma in ogni caso il tipo di variabile deve essere noto al compilatore.

Se sei nella posizione di non sapere cosa sia o potrebbe essere, è perché hai progettato qualcosa poiché il linguaggio ha un sistema di tipi dinamico.

Se questo è il caso, è meglio che tu ripensi il tuo progetto, poiché sta andando in una terra non naturale per la lingua che stai usando (più come andare in autostrada con un bruco, o in acqua con una macchina)


Se C ++ ha la modifica dinamica, penso che sarebbe fantastico e anche le funzioni typeof e parseInt, parseFloat saranno utili, ma non so perché i produttori di C ++ lo rendano troppo difficile, per esempio! chi dice che è bravo a scrivere cout << "String"
Waqas Tahir

la determinazione è migliore !!!! #include <sstream> stringa str ("1912"); int strtointval; stringstream (str) >> strtointval;
Waqas Tahir

@ Waqas Uh, cosa? Le persone che dicono che è meglio sono le persone che definiscono la lingua, e IMO hanno praticamente l'ultima parola su qualsiasi cosa a che fare con esso - buone pratiche di codifica, per esempio. Potresti riformulare quel commento in modo che abbia più senso?
Finanzia la causa di Monica il

Sono totalmente in disaccordo. Java, C #, PHP, Perl, Python e così via sono stati progettati in C e C ++ e non sono bruchi. (Quando si crea un'applicazione di database per aprire tabelle di variabili da database "sconosciuti" è necessario controllare il tipo di campo per lo schema di variabili e vice vera in un modo "molto" dinamico;))
TomeeNS

@TomeeNS: No. Sono scritti in C e C ++, non progettati . Sono progettati per svolgere il loro lavoro e hanno un tipo dinamico anche se C e C ++ non lo fanno. Non c'è niente di strano con esso.
Emilio Garavaglia

8

Di solito, voler trovare il tipo di una variabile in C ++ è la domanda sbagliata. Tende ad essere qualcosa che ti porti dietro da linguaggi procedurali come ad esempio C o Pascal.

Se si desidera codificare comportamenti diversi a seconda del tipo, provare a conoscere ad esempio il sovraccarico delle funzioni e l' ereditarietà degli oggetti . Questo non avrà immediatamente senso nel tuo primo giorno di C ++, ma continua a farlo.


Non proprio, diciamo che hai una classe Object e una sottoclasse Book. Ora immagina di avere una scatola che può contenere molti oggetti, ma per qualche motivo vuoi elencare tutti i libri al suo interno. Il controllo del tipo è molto più semplice, quindi è necessario aggiungere un metodo "tipo" a Object e quindi sovrascriverlo su Book per restituire qualcosa come "book"
Paulo Cesar

Come con qualsiasi regola, ci sono delle eccezioni (da qui il mio "solito"!), Ei contenitori tendono ad aggiungere complessità alla teoria dei tipi. Non sono mai stato troppo interessato a contenitori di oggetti polimorfici ... nella maggior parte dei casi, i tipi di contenitori uniformi modellati sono sufficienti e sono molto più puliti.
Pontus Gagge

Non usi i modelli?
Bryan Grace,

6

Credo di avere un caso d'uso valido per l'utilizzo di typeid (), allo stesso modo in cui è valido usare sizeof (). Per una funzione template, ho bisogno di un caso speciale del codice basato sulla variabile template, in modo da offrire la massima funzionalità e flessibilità.

È molto più compatto e gestibile rispetto all'utilizzo del polimorfismo, per creare un'istanza della funzione per ogni tipo supportato. Anche in quel caso potrei usare questo trucco per scrivere il corpo della funzione solo una volta:

Si noti che poiché il codice utilizza modelli, l'istruzione switch seguente dovrebbe risolversi staticamente in un solo blocco di codice, ottimizzando tutti i casi falsi, AFAIK.

Considera questo esempio, in cui potrebbe essere necessario gestire una conversione se T è un tipo rispetto a un altro. Lo uso per la specializzazione di classe per accedere all'hardware in cui l'hardware utilizzerà il tipo myClassA o myClassB. In caso di mancata corrispondenza, è necessario dedicare tempo alla conversione dei dati.

switch ((typeid(T)) {
  case typeid(myClassA):
    // handle that case
    break;
  case typeid(myClassB):
    // handle that case
    break;
  case typeid(uint32_t):
    // handle that case
    break;
  default:
    // handle that case
}

1
TypeId: non sono stato in grado di utilizzare typeid () su Arduino. Anche typeid () è un controllo in fase di esecuzione , non in fase di compilazione, quindi non può essere utilizzato per generare codice ottimizzato.
Dan Truong,

1
Sì, no, questo non fa quello che pensavi che facesse. typeidsemplicemente non può essere un controllo statico in fase di compilazione - per definizione - quindi questo non facilita alcuna ottimizzazione. For a template function, I need to special case the code based on the template variableBene, quindi quello che vuoi veramente è il polimorfismo statico tramite l'idioma CRTP. Questo è esattamente ciò che si ottiene.
underscore_d

4

Non sono sicuro che la mia risposta aiuterebbe.

La risposta breve è che non hai davvero bisogno / vuoi sapere il tipo di variabile per usarla.

Se hai bisogno di dare un tipo a una variabile statica, puoi semplicemente usare auto.

Nel caso più sofisticato in cui si desidera utilizzare "auto" in una classe o in una struttura, suggerirei di utilizzare template con decltype.

Ad esempio, supponiamo che tu stia usando la libreria di qualcun altro e che abbia una variabile chiamata "unknown_var" e vorresti metterla in un vettore o in una struttura, puoi farlo totalmente:

template <typename T>
struct my_struct {
    int some_field;
    T my_data;
};
vector<decltype(unknown_var)> complex_vector;
vector<my_struct<decltype(unknown_var)> > simple_vector

Spero che questo ti aiuti.

EDIT: Per buona misura, ecco il caso più complesso a cui posso pensare: avere una variabile globale di tipo sconosciuto. In questo caso avresti bisogno di c ++ 14 e di una variabile template.

Qualcosa come questo:

template<typename T> vector<T> global_var;

void random_func (auto unknown_var) {
    global_var<decltype(unknown_var)>.push_back(unknown_var);
}

È ancora un po 'noioso ma è il più vicino possibile alle lingue senza tipizzazione. Assicurati solo ogni volta che fai riferimento alla variabile del modello, inserisci sempre la specifica del modello lì.


2
#include <typeinfo>

...
string s = typeid(YourClass).name()

0

Se devi fare un confronto tra una classe e un tipo noto, ad esempio:

class Example{};
...
Example eg = Example();

Puoi usare questa riga di confronto:

bool isType = string( typeid(eg).name() ).find("Example") != string::npos;

che controlla che il typeidnome contenga il tipo stringa (il nome typeid ha altri dati alterati, quindi è meglio fare un s1.find(s2)invece di ==).


-2

Puoi sicuramente cercare typeid(x).name()dove x è il nome della variabile. Restituisce effettivamente un puntatore a un carattere const al tipo di dati. Ora guarda il seguente codice.

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n = 36;
    char c = 'A';
    double d = 1.2;
    if(*(typeid(n).name()) == 'i'){
        cout << "I am an Integer variable" << endl;
    }
    if(*((char *) typeid(d).name()) == 'd'){
        cout << "I am a Double variable" << endl;
    }
    if(*((char *) typeid(c).name()) == 'c'){
        cout << "I am a Char variable" << endl;
    }
    return 0;
}

Notare come il primo e il secondo funzionano entrambi.


Riconoscere il tipo dal primo carattere è una pessima idea.
Dmitry Kuzminov

Puoi essere più specifico Dmitry? Non ho capito il tuo punto qui.
Pikachu

Questo può essere abbreviato in std::cout << "I'm a variable of type " << typeid(n).name(). (riformulato per evitare artefatti, ma può essere risolto con un altro controllo). Anche allora, se vuoi assolutamente un confronto, è molto meglio farlotypeid(n) == typeid(int)
Zoe
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.