250

In C++, how does one find the type of a variable?

David G
  • 94,763
  • 41
  • 167
  • 253

11 Answers11

271

You can use the typeid operator:

#include <typeinfo>
...
cout << typeid(variable).name() << endl;
Ernir
  • 333
  • 1
  • 8
  • 17
Rich O'Kelly
  • 41,274
  • 9
  • 83
  • 114
  • 19
    @David - So `i` means integer on your compiler. The names returned are not specified by the standard. – Bo Persson Jul 03 '12 at 12:59
  • 28
    When I use it on vector it returns St6vectorIiSaIiEE. WTF? – Boyan Kushlev Jan 29 '16 at 12:19
  • 4
    @BobbyBrown you are not alone!! https://www.google.co.uk/webhp#safe=off&q=St6vectorIiSaIiEE – Rich O'Kelly Jan 31 '16 at 21:33
  • 11
    The names returned by `typeid` are very abbreviated, compiler-specific, and not intended for human consumption. You can "demangle" them (that's the actual term!), either in code with something like https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html, with command line utilities such as `c++filt`, or with any of various online demanglers such as https://demangler.com/. – cincodenada Dec 11 '18 at 19:14
60

For static assertions, C++11 introduced decltype which is quite useful in certain scenarios.

Nae
  • 14,209
  • 7
  • 52
  • 79
  • 11
    `decltype` can be used for more than just static assertions. For example, `decltype(a) b;` declares `b` as the same type as `a`. – Kai Petzke Sep 14 '20 at 14:23
  • 3
    simple example of how to use this function would be appreciated, at least for those, like me, who are learning the language for the first time... – An old man in the sea. May 01 '22 at 21:02
23

If you have a variable

int k;

You can get its type using

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

See the following thread on SO: Similar question

Community
  • 1
  • 1
Amit
  • 13,134
  • 17
  • 77
  • 148
16

The main difference between C++ and Javascript is that C++ is a static-typed language, wile javascript is dynamic.

In dynamic typed languages a variable can contain whatever thing, and its type is given by the value it holds, moment by moment. In static typed languages the type of a variable is declared, and cannot change.

There can be dynamic dispatch and object composition and subtyping (inheritance and virtual functions) as well as static-dispatch and supertyping (via template CRTP), but in any case the type of the variable must be known to the compiler.

If you are in the position to don't know what it is or could be, it is because you designed something as the language has a dynamic type-system.

If that's the case you had better to re-think your design, since it is going into a land not natural for the language you are using (most like going in a motorway with a caterpillar, or in the water with a car)

Emilio Garavaglia
  • 20,229
  • 2
  • 46
  • 63
  • If C++ has the dynamic changing then I think it would be great and typeof and parseInt,parseFloat functions will also come in handy but I don't know why C++ makers make it too hard, for example! who says its good to write cout << "String" – Waqas Tahir Aug 04 '15 at 16:17
  • determination is best!!!! #include string str("1912"); int strtointval; stringstream(str) >> strtointval; – Waqas Tahir Aug 04 '15 at 16:22
  • @Waqas Uh, what? The people who say it's best are the people who define the language, and IMO they have pretty much the final say in anything to do with it -- good coding practices, for example. Could you rephrase that comment so it makes more sense? – Nic Feb 04 '16 at 19:22
  • I totally disagree. Java, C#, PHP, Perl, Python and so on were designed in C and C++ and they are not caterpillars. (When you create an database application to open variable tables from 'unknown' databases you need to control field type to variable scheme and vice vera in a 'very' dymanic way ;) ) – TomeeNS Sep 20 '17 at 14:02
  • 1
    @TomeeNS: Nope. They are *written* in C and C++, not *designed*. They are designed to do their jobs.They have dynamic type even if C and C++ themselves don't. That's nothing strange with it. – Emilio Garavaglia Oct 02 '17 at 13:33
11

I believe I have a valid use case for using typeid(), the same way it is valid to use sizeof(). For a template function, I need to special case the code based on the template variable, so that I offer maximum functionality and flexibility.

It is much more compact and maintainable than using polymorphism, to create one instance of the function for each type supported. Even in that case I might use this trick to write the body of the function only once:

Note that because the code uses templates, the switch statement below should resolve statically into only one code block, optimizing away all the false cases, AFAIK.

Consider this example, where we may need to handle a conversion if T is one type vs another. I use it for class specialization to access hardware where the hardware will use either myClassA or myClassB type. On a mismatch, I need to spend time converting the data.

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
  • 119
  • 1
  • 5
  • 2
    TypeId: I was not able to use typeid() on Arduino. Also typeid() is a *runtime* check, not compile time so it cannot be used to generate optimized code. – Dan Truong Jun 10 '16 at 01:21
  • 1
    Yeah, no, this doesn't do what you thought it did. `typeid` simply cannot be a static, compile-time check - by definition - so this doesn't facilitate any optimisation. `For a template function, I need to special case the code based on the template variable` Right, so what you really want is static polymorphism via the CRTP idiom. This is exactly what that achieves. – underscore_d Aug 27 '16 at 12:48
  • @Dan that's because `typeid()` relies on [RTTI](https://learn.microsoft.com/en-us/cpp/cpp/run-time-type-information?view=msvc-160), which isn't guaranteed on all platforms. – glibg10b Sep 18 '21 at 08:45
9

Usually, wanting to find the type of a variable in C++ is the wrong question. It tends to be something you carry along from procedural languages like for instance C or Pascal.

If you want to code different behaviours depending on type, try to learn about e.g. function overloading and object inheritance. This won't make immediate sense on your first day of C++, but keep at it.

Pontus Gagge
  • 17,166
  • 1
  • 38
  • 51
  • 2
    Not really, let's say you have a class Object, and a subclass Book. Now imagine you have a Box that can store a lot of Objects, but for some reason you want to list all Books inside it. Checking the type is much cleaner then having to add a method "type" to Object and then override it on Book to return something like "book" – Paulo Cesar Jun 26 '18 at 09:55
  • As with any rule, there are exceptions (hence my 'usually'!), and containers do tend add complexity to the type theory. I've never been overfond of containers-of-polymorphic-objects… in most cases, templated uniform container types suffice and are much cleaner. – Pontus Gagge Jun 27 '18 at 09:50
  • Do you not use templates? – Bryan Grace Feb 18 '20 at 20:32
5

I'm not sure if my answer would help.

The short answer is, you don't really need/want to know the type of a variable to use it.

If you need to give a type to a static variable, then you may simply use auto.

In more sophisticated case where you want to use "auto" in a class or struct, I would suggest use template with decltype.

For example, say you are using someone else's library and it has a variable called "unknown_var" and you would want to put it in a vector or struct, you can totally do this:

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

Hope this helps.

EDIT: For good measure, here is the most complex case that I can think of: having a global variable of unknown type. In this case you would need c++14 and template variable.

Something like this:

template<typename T> vector<T> global_var;

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

It's still a bit tedious but it's as close as you can get to typeless languages. Just make sure whenever you reference template variable, always put the template specification there.

gohongyi
  • 128
  • 1
  • 7
4
#include <typeinfo>

...
string s = typeid(YourClass).name()
rad
  • 1,106
  • 7
  • 15
2

typeid Operator with abi::__cxa_demangle() (GCC / Clang only)

#include <iostream>
#include <typeinfo>
#if defined __GNUC__
#include <cxxabi.h>                     // GCC / Clang only
#endif

int main() {
    long long w;
    std::cout << typeid(w).name() << std::endl;                      // x

    #if defined __GNUC__      // GCC / Clang only
    char * name = abi::__cxa_demangle(typeid(w).name(), 0, 0, 0);
    std::cout << name << std::endl;                                  // long long
    free(name);
    #endif
}

clang online

Kuznetsov-M
  • 346
  • 7
  • 18
  • 1
    Clang supports this too. And MSVC returns nice names directly from `.name()`, so you can disable demangling with `#ifdef _MSC_VER`. – HolyBlackCat Jul 22 '22 at 22:13
  • Your macro condition is wrong. `clang-cl` also defines `__clang__`, and while I can't test it right now, I don't think it ships `__cxa_demangle` and it should return nice names directly from `.name()`. Testing just `__GNUC__` alone should work, since `clang` but not `clang-cl` should define it. Testing `_MSC_VER` should also work, it's defined by MSVC and `clang-cl`. Also, `defined A || B` should be `defined A || defined B`. – HolyBlackCat Jul 22 '22 at 22:53
  • Yes, thanks, I corrected the `if defined` construct. I checked the example by `clang` 13.0.0. It works correctly. https://rextester.com/IXJH71787 – Kuznetsov-M Jul 22 '22 at 23:17
  • I didn't say otherwise. I expect it to fail on `clang-cl`, not on `clang`. – HolyBlackCat Jul 22 '22 at 23:26
  • Oh, I don't have a chance to check `clang-cl` right now either. However, for `clang`, the `__GNUC__` macro is sufficient. If anyone can check this example for `clang-cl`, feel free to edit this code to make it cross-compile. – Kuznetsov-M Jul 22 '22 at 23:41
1

You can definitely go for typeid(x).name() where x is the variable name. It actually returns a const char pointer to the data type. Now, look at the following code.

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

Notice how first and second both if works.

Pikachu
  • 304
  • 3
  • 14
  • 2
    Recognizing the type by the first character is a very bad idea. – Dmitry Kuzminov Jan 21 '20 at 06:10
  • May you please be more specific Dmitry? I did not get your point here. – Pikachu Jan 22 '20 at 09:15
  • 1
    This can just be shortened to `std::cout << "I'm a variable of type " << typeid(n).name()`. (reworded to prevent a/an artifacts, but that can be fixed with another check). Even then, if you absolutely want a comparison, it's so much better to do `typeid(n) == typeid(int)` – Zoe Jul 05 '20 at 14:59
0

If you need to make a comparison between a class and a known type, for example:

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

You can use this comparison line:

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

which checks the typeid name contains the string type (the typeid name has other mangled data, so its best to do a s1.find(s2) instead of ==).

jackw11111
  • 1,457
  • 1
  • 17
  • 34