views:

5957

answers:

8

Is it possible in standard C++ to print a variable type. I think this is being addressed in C++0x but not sure it already exists.

I would like something like this:

int a = 12;
cout << typeof(a) << endl;

That would print:

int
+18  A: 

Try

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

You might have to activate RTTI in your compiler options for this to work. Additionally, the output of this depends on the compiler. It might be a raw type name or a name mangling symbol or anything in between.

Konrad Rudolph
A: 

Not in ANSI

/Dan

Care to elaborate ? Konrad Rudolph and mdec's solutions are standard C++...
paercebal
i agree with this guy. what the original poster asked for is not possible
Johannes Schaub - litb
A: 

You may be looking for this: http://www.boostpro.com/vault/

look for the file identification-v0.1.zip

+11  A: 

EDIT: Beaten, serves me right for looking it up =]. Don't forget to include <typeinfo>

I believe what you are referring to is runtime type identification. You can achieve the above by doing .

#include <iostream>
#include <typeinfo>

using namespace std;

int main() {

int i;

cout << typeid(i).name();

return 0;
}
mdec
+3  A: 

You could use a traits class for this. Something like:

#include <iostream>
using namespace std;

template <typename T> class type_name {
public:
    static const char *name;
};

#define DECLARE_TYPE_NAME(x) template<> const char *type_name<x>::name = #x;
#define GET_TYPE_NAME(x) (type_name<typeof(x)>::name)

DECLARE_TYPE_NAME(int);

int main()
{
    int a = 12;
    cout << GET_TYPE_NAME(a) << endl;
}

The DECLARE_TYPE_NAME define exists to make your life easier in declaring this traits class for all the types you expect to need.

This might be more useful than the solutions involving typeid because you get to control the output. For example, using typeid for long long on my compiler gives "x".

Greg Hewgill
+4  A: 

You can use templates.

template <typename T> const char* typeof(T&) { return "unknown"; }    // default
template<> const char* typeof(int&) { return "int"; }
template<> const char* typeof(float&) { return "float"; }

In the example above, when the type is not matched it will print "unknown".

Nick
+4  A: 

Note that the names generated by the RTTI feature of C++ is not portable. For example, the class

MyNamespace::CMyContainer<int, test_MyNamespace::CMyObject>

will have the following names:

// MSVC 2003:
class MyNamespace::CMyContainer[int,class test_MyNamespace::CMyObject]
// G++ 4.2:
N8MyNamespace8CMyContainerIiN13test_MyNamespace9CMyObjectEEE

So you can't use this information for serialization. But still, the typeid(a).name() property can still be used for log/debug purposes

paercebal
A: 

The other answers involving RTTI (typeid) are probably what you want, as long as:

  • you can afford the memory overhead (which can be considerable with some compilers)
  • the class names your compiler returns are useful

The alternative, (similar to Greg Hewgill's answer), is to build a compile-time table of traits.

template <typename T> struct type_as_string;

// declare your Wibble type (probably with definition of Wibble)
template <> struct type_as_string<Wibble> { static const char* const value = "Wibble"; };

Be aware that if you wrap the declarations in a macro, you'll have trouble declaring names for template types taking more than one parameter (e.g. std::map), due to the comma.

To access the name of the type of a variable, all you need is

template <typename T>
const char* get_type_as_string(const T&) { return type_as_string<T>::value; }
James Hopkin
Good point about the comma, I knew there was a reason macros were a bad idea but didn't think of it at the time!
Greg Hewgill
static const char* value = "Wibble"; you can't do that mate :)
Johannes Schaub - litb