Ibujah
Ibujah

Reputation: 21

Output a template class name during compilation

I would like to know if it is possible to know and output a template class name at compile time. It would look like something like this:

template<typename T>
class SomeTemplateClass
{
    SOME_WAY_TO_PRINT_CLASS_NAME(T)
};

Then, each time the template class is called, for example:

using C = SomeTemplateClass<std::string>;

or

SomeTemplateClass<std::string> instance;

The compiler would echo a message like:

note: Template argument of SomeTemplateClass is std::__cxx11::basic_string<char>

As far as I searched, I found one way, that crashes the compiler to give the type of the class:

template<typename T>
class SomeTemplateClass
{
    public:
    using print = typename T::expected_crash;
};

using C = SomeTemplateClass<std::string>;

int main()
{
    C::print err;
    return 0;
}

That gives:

error: no type named ‘expected_crash’ in ‘class std::__cxx11::basic_string<char>’

But it is more a hack than a clean solution, and I was wondering if there was an other solution to this problem.

Thanks!

Upvotes: 2

Views: 442

Answers (3)

Ibujah
Ibujah

Reputation: 21

There is an other hacky way to output a template class name at compilation, but without crashing the compiler. It is possible to use a warning, here a unused variable warning.

#define PRINT(T) template<typename T> \
int print_##T() \
{ \
    int type_of_##T = 0; \
    return 0; \
};\
int res_##T = print_##T<T>();

With this (and the -Wunused-variable flag), you can write

PRINT(T)

to know the type of T. Moreover, it is possible to use this solution inside a class, by creating a method, like this:

template<typename T>
class SomeTemplateClass
{
    public:
        static int print()
        {
            int type_of_T = 0;
            return 0;
        };
};

Method that will be called outside:

int useless = SomeTemplateClass<T>::print();

So it is still a hack, but at least the compiler does not crash any more.

Upvotes: 0

Max Langhof
Max Langhof

Reputation: 23711

This template has a dependent static_assert that will always fail. Compilers usually show the template parameters that caused such an instantiation to fail.

template<class T>
struct NameOf {
    static_assert(sizeof(T) != sizeof(T), "");
};

Demo

<source>: In instantiation of 'struct NameOf<SomeClass>':                  // <---
<source>:18:15:   required from 'void foo(const T&) [with T = SomeClass]'  // <---
<source>:24:10:   required from here
<source>:9:29: error: static assertion failed
9 |     static_assert(sizeof(T) != sizeof(T), "");
  |                   ~~~~~~~~~~^~~~~~~~~~~~

You can do the same to have your compiler tell you the compile-time value of an arbitrary integer:

template<int I>
struct CompileTimeValueOf {
    static_assert(I != I, "");
};

CompileTimeValueOf<sizeof(double)> x;

Note that this will of course make compilation fail, so it's just for temporary inspection. For anything less destructive, you'll probably have to resort to compiler-specific extensions. See for example here.

Upvotes: 0

Korni
Korni

Reputation: 464

You can use typeid(T).name() to determine the name of the Class.

Upvotes: 1

Related Questions