4

This needs only work in g++.

I want a function

template<typename T> std::string magic();

such that:

Class Foo{}; magic<Foo>(); // returns "Foo";
Class Bar{}; magic<Bar>(); // returns "Bar";

I don't want this to be done via specialization (i.e. having to define magic for each type. I'm hoping to pull some macro/template black magic here. Anyone know how?)

Thanks!

skaffman
  • 398,947
  • 96
  • 818
  • 769
anon
  • 41,035
  • 53
  • 197
  • 293
  • 1
    Now what part of that is necessary and what part are you just writing because you think it's needed. Is class Foo important? Give us a more realistic use case. – James Curran Feb 16 '10 at 04:22
  • 1
    Its a fairly obvious requirement for some kind of simple static reflection mechanism, that doesn't bring in the full gamut of RTTI. – Justicle Feb 16 '10 at 04:33
  • I want to have a function that I can pass it any type, and it'll return for me the name of the type. – anon Feb 16 '10 at 05:01
  • In *C++* probably you are looking template black magic. If so, [Modern C++ Design](http://en.wikipedia.org/wiki/Modern_C%2B%2B_Design) will be helpful. – Andy Feb 19 '10 at 12:13

4 Answers4

11

To convert a type (or other identifer) into a string you need a macro, but a macro can not check if it's parameter is a valid type. To add type checking a template function can be added to the macro:

template<typename T>
std::string magic_impl(const char *name) { return name; }

#define more_magic(a) magic_impl<a>(#a)
#define magic(a) more_magic(a)

Here magic(int) gives the string "int" while magic(Foo) gives a "‘Foo’ was not declared" error if there is no such class.

sth
  • 222,467
  • 53
  • 283
  • 367
  • Of all the answers given here I like this answer the best because a) It does typechecking b) The result is the class name and not any mangled form which may be compiler dependent. – ardsrk Feb 16 '10 at 04:48
  • 1
    more_magic exists just to check that a type named "a" is declared and is in scope. Without that I could call magic(%%%%) and get the call to succeed even though %%%% couldn't have been a legal name for a type. – ardsrk Feb 16 '10 at 11:18
8

Try typeid(Foo).name() for a start. Parse as you see fit; will be implementation-dependent (but simply getting a string back is portable).

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
4

The stringizing operator on macros may be what you're looking for:

#define MAGICCLASSNAME(str) std::string magic(#str)
class Foo{}; MAGICCLASSNAME(foo)
David Gladfelter
  • 4,175
  • 2
  • 25
  • 25
1

I have come up with the below:

#include <iostream>
#include <string>
#include <typeinfo>

using namespace std;
class Foo{}; 
class Bar{};

template<typename T> 
inline std::string magic(const T& obj)
{
 return typeid(obj).name();
}

int main()
{
 Foo a;
 cout << magic<Foo>(a); // returns "Foo";
}

I tested this with g++ and works well.

Also I got it from this SO answer.

Community
  • 1
  • 1
ardsrk
  • 2,407
  • 2
  • 21
  • 33