Jak uzyskać typ zmiennej?

131

Jak w C ++ znaleźć typ zmiennej?

0x499602D2
źródło
7
cout << typeid (zmienna) .name () << endl;
SRN,
2
Skorzystaj z wyszukiwarki lub google :) stackoverflow.com/questions/81870/print-variable-type-in-c Najostrzejsze jest szybkie: D
Kariboo
14
@Kariboo, korzystałem z Google i wysłano mnie tutaj.
Michael Warner,
To pytanie jest bardzo niejasne i nawet po obejrzeniu różnych odpowiedzi; nie jest bynajmniej jasne, że pytanie to szuka akceptowanej odpowiedzi.
Antti Haapala

Odpowiedzi:

159

Możesz użyć operatora typeid :

#include <typeinfo>
...
cout << typeid(variable).name() << endl;
Rich O'Kelly
źródło
15
@David - Więc ioznacza liczbę całkowitą na twoim kompilatorze. Zwracane nazwy nie są określone przez standard.
Bo Persson,
11
Kiedy używam go na wektorze <int>, zwraca St6vectorIiSaIiEE. WTF?
Boyan Kushlev
2
@BobbyBrown nie jesteś sam !! google.co.uk/webhp#safe=off&q=St6vectorIiSaIiEE
Rich O'Kelly
5
Nazwy zwracane przez typeidsą bardzo skrócone, specyficzne dla kompilatora i nie są przeznaczone do spożycia przez ludzi. Możesz je „rozszyfrować” (to jest rzeczywisty termin!), Albo w kodzie za pomocą czegoś takiego jak gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html , za pomocą narzędzi wiersza poleceń, takich jak c++filt, lub za pomocą dowolnego z różnych demanglerów online takie jak demangler.com .
cincodenada
33

W przypadku stwierdzeń statycznych wprowadzono C ++ 11, decltypeco jest bardzo przydatne w niektórych scenariuszach.

Nie
źródło
12

Jeśli masz zmienną

int k;

Możesz uzyskać jego typ za pomocą

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

Zobacz następujący wątek na SO: Podobne pytanie

Amit
źródło
9

Główną różnicą między C ++ a Javascriptem jest to, że C ++ jest językiem z typowaniem statycznym, a wile javascript jest dynamiczny.

W językach z typami dynamicznymi zmienna może zawierać dowolną rzecz, a jej typ jest określony chwilą przez wartość, jaką posiada. W językach statycznych typ zmiennej jest deklarowany i nie można go zmienić.

Może istnieć dynamiczne wysyłanie i skład obiektów i podtypowanie (dziedziczenie i funkcje wirtualne), a także wysyłanie statyczne i supertyping (za pośrednictwem szablonu CRTP), ale w każdym przypadku kompilator musi znać typ zmiennej.

Jeśli możesz nie wiedzieć, co to jest lub może być, to dlatego, że coś zaprojektowałeś, ponieważ język ma dynamiczny system typów.

Jeśli tak jest, lepiej przemyśleć swój projekt, ponieważ wjeżdża on do krainy, która nie jest naturalna dla języka, którego używasz (najbardziej przypomina jazdę autostradą z gąsienicą lub jazdę samochodem w wodzie)

Emilio Garavaglia
źródło
Jeśli C ++ ma dynamiczną zmianę, myślę, że byłoby świetnie, a funkcje typu i parseInt, parseFloat również się przydadzą, ale nie wiem, dlaczego twórcy C ++ na przykład utrudniają to! kto mówi, że dobrze jest napisać cout << "String"
Waqas Tahir
determinacja jest najlepsza !!!! #include <sstream> string str ("1912"); int strtointval; stringstream (str) >> strtointval;
Waqas Tahir
@Waqas Uh, co? Ludzie, którzy twierdzą, że jest najlepszy, to ludzie, którzy definiują język, a IMO mają prawie ostatnie słowo z nim związane - na przykład dobre praktyki kodowania. Czy mógłbyś przeformułować ten komentarz, aby miał więcej sensu?
Załóż pozew Moniki
Całkowicie się nie zgadzam. Java, C #, PHP, Perl, Python i tak dalej zostały zaprojektowane w C i C ++ i nie są gąsienicami. (Kiedy tworzysz aplikację bazodanową do otwierania tabel zmiennych z 'nieznanych' baz danych, musisz kontrolować typ pola na schemat zmiennych i vice vera w 'bardzo' dynamiczny sposób;))
TomeeNS
@TomeeNS: Nie. Są napisane w C i C ++, a nie zaprojektowane . Są przeznaczone do wykonywania swoich zadań i mają typ dynamiczny, nawet jeśli same C i C ++ tego nie robią. Nie ma w tym nic dziwnego.
Emilio Garavaglia
8

Zwykle chęć znalezienia typu zmiennej w C ++ jest złym pytaniem. Zwykle jest to coś, co nosisz z języków proceduralnych, takich jak na przykład C lub Pascal.

Jeśli chcesz zakodować różne zachowania w zależności od typu, spróbuj dowiedzieć się np. O przeciążaniu funkcji i dziedziczeniu obiektów . Nie będzie to miało natychmiastowego sensu pierwszego dnia C ++, ale trzymaj się tego.

Pontus Gagge
źródło
Niezupełnie, powiedzmy, że masz klasę Object i podklasę Book. Teraz wyobraź sobie, że masz pudełko, które może przechowywać wiele obiektów, ale z jakiegoś powodu chcesz wyświetlić listę wszystkich książek w nim. Sprawdzanie typu jest dużo czystsze niż dodanie metody „type” do Object, a następnie zastąpienie jej w Book, aby otrzymać coś takiego jak „book”
Paulo Cesar
Jak w przypadku każdej reguły, istnieją wyjątki (stąd moje „zwykle”!), A kontenery mają tendencję do zwiększania złożoności teorii typów. Nigdy nie przepadałem za pojemnikami-obiektami-polimorficznymi… w większości przypadków, szablony jednorodnych typów pojemników są wystarczające i są znacznie czystsze.
Pontus Gagge
Nie używasz szablonów?
Bryan Grace
6

Uważam, że mam ważny przypadek użycia dla używania typeid (), w ten sam sposób, w jaki jest ważne, aby użyć sizeof (). W przypadku funkcji szablonu potrzebuję specjalnego przypadku kodu opartego na zmiennej szablonu, aby zaoferować maksymalną funkcjonalność i elastyczność.

Tworzenie jednej instancji funkcji dla każdego obsługiwanego typu jest znacznie bardziej zwarte i łatwiejsze w utrzymaniu niż użycie polimorfizmu. Nawet w takim przypadku mógłbym użyć tej sztuczki, aby napisać treść funkcji tylko raz:

Zwróć uwagę, że ponieważ kod używa szablonów, poniższa instrukcja switch powinna zostać rozwiązana statycznie tylko do jednego bloku kodu, optymalizując wszystkie fałszywe przypadki, AFAIK.

Rozważ ten przykład, w którym może być konieczne obsłużenie konwersji, jeśli T jest jednym z typów. Używam go do specjalizacji klasowej, aby uzyskać dostęp do sprzętu, w którym sprzęt będzie używał typu myClassA lub myClassB. W przypadku niezgodności muszę poświęcić czas na konwersję danych.

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
}
Dan Truong
źródło
1
TypeId: nie udało mi się użyć typeid () na Arduino. Również typeid () jest sprawdzaniem w czasie wykonywania , a nie czasem kompilacji, więc nie może być używane do generowania zoptymalizowanego kodu.
Dan Truong,
1
Tak, nie, to nie robi tego, co myślałeś. typeidpo prostu nie może być statyczną kontrolą czasu kompilacji - z definicji - więc nie ułatwia to żadnej optymalizacji. For a template function, I need to special case the code based on the template variableTak, więc to, czego naprawdę chcesz, to statyczny polimorfizm za pośrednictwem idiomu CRTP. Dokładnie to osiąga.
underscore_d
4

Nie jestem pewien, czy moja odpowiedź pomogłaby.

Krótka odpowiedź brzmi: tak naprawdę nie potrzebujesz / nie chcesz znać typu zmiennej, aby jej użyć.

Jeśli chcesz nadać typ zmiennej statycznej, możesz po prostu użyć auto.

W bardziej wyrafinowanym przypadku, gdy chcesz użyć „auto” w klasie lub strukturze, sugerowałbym użycie szablonu z decltype.

Na przykład, powiedzmy, że korzystasz z biblioteki innej osoby i ma ona zmienną o nazwie „unknown_var” i chcesz umieścić ją w wektorze lub strukturze, możesz całkowicie to zrobić:

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

Mam nadzieję że to pomoże.

EDYCJA: Na dokładkę, oto najbardziej złożony przypadek, jaki przychodzi mi do głowy: posiadanie zmiennej globalnej nieznanego typu. W takim przypadku potrzebujesz C ++ 14 i zmiennej szablonu.

Coś takiego:

template<typename T> vector<T> global_var;

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

Wciąż jest to trochę uciążliwe, ale jest tak bliskie, jak to tylko możliwe, do języków bez maszyny. Po prostu upewnij się, że za każdym razem, gdy odwołujesz się do zmiennej szablonu, zawsze umieszczaj tam specyfikację szablonu.

gohongyi
źródło
2
#include <typeinfo>

...
string s = typeid(YourClass).name()
rad
źródło
0

Jeśli chcesz dokonać porównania między klasą a znanym typem, na przykład:

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

Możesz użyć tej linii porównawczej:

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

która sprawdza, czy typeidnazwa zawiera typ string (nazwa typu typeid ma inne zniekształcone dane, więc najlepiej jest zrobić s1.find(s2)zamiast ==).

jackw11111
źródło
-2

Zdecydowanie możesz wybrać, typeid(x).name()gdzie x jest nazwą zmiennej. W rzeczywistości zwraca wskaźnik const char do typu danych. Teraz spójrz na poniższy kod.

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

Zwróć uwagę, jak działa pierwszy i drugi.

Pikaczu
źródło
Rozpoznawanie typu przez pierwszą postać to bardzo zły pomysł.
Dmitry Kuzminov
Czy możesz być bardziej konkretny, Dmitry? Nie rozumiem, o co ci tutaj chodzi.
Pikachu
Można to po prostu skrócić do std::cout << "I'm a variable of type " << typeid(n).name(). (przeredagowano, aby zapobiec artefaktom / an, ale można to naprawić za pomocą innego sprawdzenia). Nawet wtedy, jeśli absolutnie chcesz porównania, o wiele lepiej to zrobićtypeid(n) == typeid(int)
Zoe,