83

While playing with templates in c++ I encountered a problem converting typename T to string. For example:

template <typename T>
class Matrix {
   public:
        Matrix() {
           //my_type = string type of T. i.e. if T is char. I want my_type to be "char".
        }
   string my_type;
}

How do I convert T to a string that says what T is.

Note: I'm just playing around so please do not worry about when one might need such a thing.

svick
  • 236,525
  • 50
  • 385
  • 514
Srikanth
  • 11,564
  • 3
  • 23
  • 28

7 Answers7

82

There is no built-in mechanism for this.

typeid(T)::name() can give some info, but the standard does not mandate this string to be human-readable; just that it has to be distinct for each type. (E.x. Microsoft Visual C++ uses human-readable strings; GCC does not.)

You can build your own system though. For example, traits-based. Something like this:

// default implementation
template <typename T>
struct TypeName
{
    static const char* Get()
    {
        return typeid(T).name();
    }
};

// a specialization for each type of those you want to support
// and don't like the string returned by typeid
template <>
struct TypeName<int>
{
    static const char* Get()
    {
        return "int";
    }
};

// usage:
const char* name = TypeName<MyType>::Get();
Olivia Stork
  • 4,660
  • 5
  • 27
  • 40
atzz
  • 17,507
  • 3
  • 35
  • 35
25

For GCC you have to use a trick. Using cxxabi.h, I wrote a little wrapper for this purpose:

#include <string>
#include <iostream>
#include <iomanip>
#include <typeinfo>
#include <cxxabi.h>

#define DEBUG_TYPE(x) do { typedef void(*T)x; debug_type<T>(T(), #x); } while(0)

template<typename T>
struct debug_type
{
    template<typename U>
    debug_type(void(*)(U), const std::string& p_str)
    {
        std::string str(p_str.begin() + 1, p_str.end() - 1);
        std::cout << str << " => ";
        char * name = 0;
        int status;
        name = abi::__cxa_demangle(typeid(U).name(), 0, 0, &status);
        if (name != 0) { std::cout << name << std::endl; }
        else { std::cout << typeid(U).name() << std::endl; }
        free(name);
    }
};

The double parentheses are necessary. Will work with any type.

Now you can use it for boost::mpl:

DEBUG_TYPE((if_c<true, true_, false_>::type));

will print:

if_c<true, true_, false_>::type => bool_<true>
Olivia Stork
  • 4,660
  • 5
  • 27
  • 40
  • would this not make it processor-specific for the Itanium 64-bit ?? or is this usable on other architectures? – serup Jul 13 '17 at 19:22
  • 2
    @serup abi::__cxa_demanble should be available with gcc on any architecture (e.g. I've used it on ARM). – Loss Mentality Oct 25 '19 at 02:48
7

You can't, at least not directly. The only way to convert a token or series of tokens into a string literal is using the preprocessor's stringization operator (#) inside of a macro.

If you want to get a string literal representing the type, you'll have to write something yourself, perhaps by using a macro to instantiate the template and pass it the stringized type name.

One problem with any general approach is: what string should be given for the following uses:

Matrix<char> x;
typedef char MyChar;
Matrix<MyChar> y;

Both x and y are of the same type, but one uses char directly and the other uses the typedef MyChar.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
7

It is impossilbe to get name of type in string if the type is one of base types. For user defined types you can use typeid(my_type).name(). Also you need #include <typeinfo> :) more info...

Mihran Hovsepyan
  • 10,810
  • 14
  • 61
  • 111
1

workaround way...

#define Tprint(x) print<x>(#x)

template<typename T>
void print (string ltype){
cout<<ltype<<" = "<<sizeof(T)<<endl;
}
bland
  • 1,968
  • 1
  • 15
  • 22
  • Excuse me for poor formatting. My first post in stackover flow. – user3071398 Dec 30 '13 at 19:53
  • 6
    I'm pretty sure that if you do `Tprint(T)` where `T` is the template parameter given in the original question, you'll get `T = 4` or some number. You won't get the type of T written to the screen. – Mark Lakata Apr 30 '15 at 18:35
0

You could use a C++ reflection library. So:

using namespace ponder;

Class::declare<Matrix>();

std::string const& name = classByType<Matrix>().name();

This gives you other options as well once you have the metaclass information, like looking what the class members are.

Nick
  • 27,566
  • 12
  • 60
  • 72
-6
template< typename From,typename To>
static inline bool superConvert(const From& fromVar,To& toVar)
{
    stringstream ss;
    ss<<fromVar;
    ss>>toVar;
    if(ss.fail())
    {
        return false;
    }
    else
    {
        From tempFrom;
        stringstream ss;
        ss<<toVar;
        ss>>tempFrom;
        if(tempFrom != fromVar)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
}
Ajish Kb
  • 460
  • 1
  • 4
  • 11