Print Template Typename at Compile Time

Print template typename at compile time

__PRETTY_FUNCTION__ should solve your problem (at run time at least)

The output to the program below is:

asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
!!!Hello World!!!

If you really, really, need the typename as a string, you could hack this (using snprintf instead of printf) and pull the substring after '=' and before ']'.

#include <iostream>
using namespace std;

template<typename type>
class test
{
public:
test()
{
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
}
};

template<typename type>
void tempFunction()
{
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
}

int main() {
test<int> test;

tempFunction<bool>();
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
return 0;
}

Print a type's name at compile time without aborting compilation?

The following mechanism is due to @JonathanWakely, and is specific to GCC:

int i;

template <typename T>
[[gnu::warning("your type here")]]
bool print_type() { return true; }

bool b = print_type<decltype(i)>();

This gives you:

<source>:In function 'void __static_initialization_and_destruction_0(int, int)':
<source>:7:33: warning: call to 'print_type<int>' declared with attribute warning: your
type here [-Wattribute-warning]
7 | bool b = print_type<decltype(i)>();
| ~~~~~~~~~~~~~~~~~~~~~~~^~

See it working on Godbolt.

Print deduced template arguments at compile time

Here's one (admittedly roundabout and verbose) approach:

#include <utility>

template <class T>
struct type_reader {
type_reader() {
int x{0};
if (x = 1) {} // trigger deliberate warning
}
};

int main() {
std::pair x(1, 2.0);
type_reader<decltype(x)> t;
}

Depending on your compiler and settings, you can get a warning like

<source>:7:19: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
if (x = 1) {} // trigger deliberate warning
<source>:13:34: note: in instantiation of member function 'type_reader<std::pair<int, double>>::type_reader' requested here
type_reader<decltype(x)> t;

and you can see the type std::pair<int, double>> in that mess if you squint.

Printing a compile-time string_view

Here's a modification of OP's solution that produces a somewhat more readable message with gcc. Unfortunately, with clang the message is rather less readable, and MSVC doesn't work at all (due to a compiler bug I suppose).

#include <cstdlib>
#include <algorithm>
#include <string_view>
#include <utility>

template <size_t N> struct FS { // fixed size string
char chars[N + 1] = {};
constexpr FS(const char (&str)[N + 1]) {
std::copy_n(str, N + 1, chars);
}
};

template <size_t N> FS(const char (&str)[N])->FS<N - 1>;

template<typename T>
struct type_to_string;

template<>
struct type_to_string<int> { constexpr static auto value = "integer"; };

template <auto>
constexpr bool string_value = false;

template<FS fs> // size will be deduced
void compile_time_display() {
static_assert(string_value<fs>);
}

int main()
{
constexpr std::string_view sv = type_to_string<int>::value;
constexpr size_t n = sv.size();
constexpr auto indices = std::make_index_sequence<n>();

[&] <std::size_t... I>
(std::index_sequence<I...>)
{
static constexpr char text[] { (char)sv.at(I)..., 0 };
compile_time_display<text>(); // the char array will convert to FS

}(indices);
}

The message shown by gcc reads:

main.cc: In instantiation of ‘void compile_time_display() 
[with FS<...auto...> fs = FS<7>{"integer"}]’
...
main.cc:26:23: note: ‘string_value<FS<7>{"integer"}>’ evaluates to false

C++ Get name of type in template

Jesse Beder's solution is likely the best, but if you don't like the names typeid gives you (I think gcc gives you mangled names for instance), you can do something like:

template<typename T>
struct TypeParseTraits;

#define REGISTER_PARSE_TYPE(X) template <> struct TypeParseTraits<X> \
{ static const char* name; } ; const char* TypeParseTraits<X>::name = #X

REGISTER_PARSE_TYPE(int);
REGISTER_PARSE_TYPE(double);
REGISTER_PARSE_TYPE(FooClass);
// etc...

And then use it like

throw ParseError(TypeParseTraits<T>::name);

EDIT:

You could also combine the two, change name to be a function that by default calls typeid(T).name() and then only specialize for those cases where that's not acceptable.

How to output c++ type information during compilation

The preprocessor is not going to help you much itself at compile time. It's job is preprocessing, which happens before compile time.

If the idea is to output type information at compile time then try the following

template <typename...> struct WhichType;
class Something {};

int main() {
WhichType<Something>{};
}

Live example here. When you compile this you should get an error that gives you the type of whatever is inside the templates when trying to instantiate WhichType. This was a neat trick I picked up from Scott Meyers' Effective Modern C++ book. It seems to work perfectly on most mainstream compilers that I have encountered so far.

If you want to get the type information at runtime

#include <iostream>
#include <typeinfo>

using std::cout;
using std::endl;

int main() {
auto integer = int{};
cout << typeid(integer).name() << endl;
}

Note Don't get too comfortable with RTTI (RunTime Type Information) via typeid, C++ also offers several compile time type introspection utilities http://en.cppreference.com/w/cpp/header/type_traits.



Related Topics



Leave a reply



Submit