2

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!

Ibujah
  • 21
  • 1
  • 1
    I doubt you can do better than your hack. You can move the `static_assert` in a proper structure but you'd still have to make the code fails, which may not be wanted. There might be some compiler options that would give you a more verbose compilation log. – Holt Aug 24 '18 at 12:44
  • Looks like you need something like concepts from C++2a. – Marek R Aug 24 '18 at 13:39
  • To prevent the crash of the compiler, is there a possibility to use a warning instead of an error to get what I want ? And I don't know anything about concepts. How does they work, and how can they be useful here ? – Ibujah Aug 26 '18 at 09:57

3 Answers3

1

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

Korni
  • 464
  • 2
  • 10
  • 3
    "to determine the name of the Class" - Well, strictly speaking, `name` just gives you a unique, implementation defined, identifier. Nothing guarantees that it's actually the class name. – Jesper Juhl Aug 24 '18 at 12:40
  • the OP ask for a template class name known a compile time; `typeid(T).name()` works run time. – max66 Aug 24 '18 at 13:26
0

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.

Max Langhof
  • 23,383
  • 5
  • 39
  • 72
  • You can go with other warnings as well, just create a ridiculous identifier which would be representative or message text. – SergeyA Aug 24 '18 at 13:26
  • @SergeyA That won't help if you have "warnings are errors" enabled, which you probably should. – Max Langhof Aug 24 '18 at 13:45
  • Pedantically `static_assert(sizeof(T) != sizeof(T), "");` is as wrong as `static_assert(false, "");` (there is no `T` which can pass the test). `static_assert(always_false::value, "");` with `template struct always_false : false_type {};` is valid(we might create dummy type and specialize `always_false` to be `std::true_type`). – Jarod42 Aug 24 '18 at 15:36
  • But it's a dependent expression, which is (in my understanding) what matters. I don't think the standard allows this kind of inference before instantiation (but I'd be curious to be proven wrong). – Max Langhof Aug 24 '18 at 16:25
  • In practice, dependent expression suffice, but standard specify [that the program is ill formed if no valid specialization can be generated for a template](http://eel.is/c++draft/temp#res-8.1) – Jarod42 Aug 27 '18 at 14:46
0

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.

Ibujah
  • 21
  • 1