How to capture the name of a class in a string at compile time ?

V

Vincent Cantin

I have a class defined by a template which needs to "say" its type to the
user via string.

As an example, here is the class that I want to fix :

template<class T> class Container : public Serializable
{
public:

T value;

static string classIdentifier;

string& getClassIdentifier();

};

template <class T> string& Container<T>::getClassIdentifier()
{
return classIdentifier;
}


For now, the only way I found to initiliaze the string is with :

string Container<bool>::classIdentifier("Container<bool>");
string Container<char>::classIdentifier("Container<char>");
string Container<short>::classIdentifier("Container<short>");
string Container<int>::classIdentifier("Container<int>");
string Container<float>::classIdentifier("Container<float>");
string Container<double>::classIdentifier("Container<double>");
string Container<unsigned char>::classIdentifier("Container<unsigned
char>");
string Container<unsigned short>::classIdentifier("Container<unsigned
short>");
string Container<unsigned int>::classIdentifier("Container<unsigned int>");
string Container<unsigned float>::classIdentifier("Container<unsigned
float>");
string Container<unsigned double>::classIdentifier("Container<unsigned
double>");

This solution works for the basis types, but now imagine that I would like
to use my template class with another type which is not in the list ? The
compiler will say that my static variable is not defined :-(

I think there might be a way to do it with a macro but I don't know how to
do. Does someone here have a solution ?

Vincent
 
J

John Harrison

Vincent Cantin said:
I have a class defined by a template which needs to "say" its type to the
user via string.

As an example, here is the class that I want to fix :

template<class T> class Container : public Serializable
{

There is no guaranteed way of doing this, but the following might work on
some compilers

#include <type_info>

template<class T> class Container : public Serializable
{
public:
std::string getClassIdentifier() const
{
return typeid(T).name();
}
...

The problem is that the C++ standard does not make any guarantees as to what
the name() method returns, but some compilers implement it to return a human
readable name.

john
 
A

Alex Vinokur

Vincent Cantin said:
I have a class defined by a template which needs to "say" its type to the
user via string.

As an example, here is the class that I want to fix :

template<class T> class Container : public Serializable
{
public:

T value;

static string classIdentifier;

string& getClassIdentifier();

};

template <class T> string& Container<T>::getClassIdentifier()
{
return classIdentifier;
}


For now, the only way I found to initiliaze the string is with :

string Container<bool>::classIdentifier("Container<bool>");
string Container<char>::classIdentifier("Container<char>");
string Container<short>::classIdentifier("Container<short>");
string Container<int>::classIdentifier("Container<int>");
string Container<float>::classIdentifier("Container<float>");
string Container<double>::classIdentifier("Container<double>");
string Container<unsigned char>::classIdentifier("Container<unsigned
char>");
string Container<unsigned short>::classIdentifier("Container<unsigned
short>");
string Container<unsigned int>::classIdentifier("Container<unsigned int>");
string Container<unsigned float>::classIdentifier("Container<unsigned
float>");
string Container<unsigned double>::classIdentifier("Container<unsigned
double>");

This solution works for the basis types, but now imagine that I would like
to use my template class with another type which is not in the list ? The
compiler will say that my static variable is not defined :-(

I think there might be a way to do it with a macro but I don't know how to
do. Does someone here have a solution ?

Vincent

If you are using GNU g++ version 3.3
the following method can be used.

========= C++ code : foo.cpp : BEGIN =========
#include <string>
#include <iostream>
using namespace std;

template<class T>
class Container
{
public:

static const string classIdentifier;
static string getClassIdentifier();
};

template<class T>
string Container<T>::getClassIdentifier()
{
const string str0 (__PRETTY_FUNCTION__);
string str1 (str0.substr (0, str0.find ("<")));
str1 = str1.substr (str1.find_last_of (' ') + 1);
string str2 (str0.substr (str0.find_last_of (' ') + 1));
str2 = str2.substr (0, str2.size() - 1);

return str1 + "<" + str2 + ">";
}

template<class T>
const string Container<T>::classIdentifier(Container<T>::getClassIdentifier());

class Foo {};


template<class T>
class Bar {};


int main ()
{
cout << Container<bool>::classIdentifier << endl;
cout << Container<int>::classIdentifier << endl;
cout << Container<Foo>::classIdentifier << endl;
cout << Container<Bar<int> >::classIdentifier << endl;
cout << Container<Bar<Foo> >::classIdentifier << endl;

cout << endl;
cout << Container<bool>().classIdentifier << endl;
cout << Container<int>().classIdentifier << endl;
cout << Container<Foo>().classIdentifier << endl;
cout << Container<Bar<int> >().classIdentifier << endl;
cout << Container<Bar<Foo> >().classIdentifier << endl;
return 0;
}
========= C++ code : foo.cpp : END ===========


========= Compilation & Run : BEGIN =========

$ g++ --version
g++ (GCC) 3.3.1 (cygming special)
[snip]

$ g++ foo.cpp

$ a

Container<bool>
Container<int>
Container<Foo>
Container<Bar<int>>
Container<Bar<Foo>>

Container<bool>
Container<int>
Container<Foo>
Container<Bar<int>>
Container<Bar<Foo>>

========= Compilation & Run : END ===========
 
J

josh

Alex said:
If you are using GNU g++ version 3.3
the following method can be used. [...]
template<class T>
string Container<T>::getClassIdentifier()
{
const string str0 (__PRETTY_FUNCTION__);
string str1 (str0.substr (0, str0.find ("<")));
str1 = str1.substr (str1.find_last_of (' ') + 1);
string str2 (str0.substr (str0.find_last_of (' ') + 1));
str2 = str2.substr (0, str2.size() - 1);

return str1 + "<" + str2 + ">";
}

Or you could go for something a little more generic:
(__FUNCSIG__ is msvc7 specific, I assume gcc's __PRETTY_FUNCTION__ would
be similar)

#include <iostream>
#include <string>

/*d::string typestring< <- must be same length */
std::string dummy(void) { return __FUNCSIG__; }

template <typename T>
std::string typestring(void)
{
std::string n = __FUNCSIG__ + dummy().size();
return n.erase(n.rfind('>'));
}

struct etc { };

template<class T> class Container { };

int main(void)
{
std::cout << typestring<int>() << '\n';
std::cout << typestring<std::string>() << '\n';
std::cout << typestring<etc>() << '\n';
std::cout << typestring<Container<Container<int> > >() << '\n';
}

Result:

int
class std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> >
struct etc
class Container<class Container<int> >

Personally, I'd probably go for something more tedious but standard.

-josh
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top