I posted this answer recently. OP in the StackOverflow question mentioned that it was for educational use, but I can imagine it being used as a debugging aid. Then I decided to improve it slightly and make it a compile-time function. Code:
#include <cassert>
#include <iostream>
#include <string_view>
#include <type_traits>
#include <vector>
#ifndef __GNUC__
static_assert(false, "GCC specific");
#endif // !__GNUC__
// Finds a character in a nul terminated string.
// Returns the last character if sought one isn't found.
// Notes:
// 1. Using this because std::strchr isn't constexpr.
// `PChr` is a separate typename instead of just using Chr* to allow `Chr*` and
// `Chr const*` as the pointer.
// 2. pstr shall not be nullptr.
template <typename PChr, typename Chr>
[[gnu::pure, gnu::nonnull, gnu::returns_nonnull, nodiscard]]
static constexpr auto*
constexpr_strchr(PChr pstr, Chr const value) noexcept {
// PChr must be a raw pointer type because of gnu::nonnull and
// gnu::returns_nonnull
static_assert(std::is_pointer_v<PChr>, "PChr must be a raw pointer type");
auto constexpr nul = Chr{};
while (*pstr != value && *pstr != nul) {
++pstr;
}
return pstr;
}
// Returns distance from ptr to the end of the array.
// Notes:
// 1. ptr shall not be nullptr
// 2. ptr shall be inside the array (arr)
template <typename T, auto size>
[[gnu::const, gnu::artificial, gnu::nonnull, gnu::always_inline, nodiscard]]
inline static constexpr auto
distance_to_end(const T (&arr)[size], T const* const ptr) noexcept {
return arr + size - ptr;
}
// Returns type T as a string_view.
// Ex: std::string -> "std::string"
template <typename T>
[[gnu::const, nodiscard]]
static constexpr auto type_name_finder() noexcept {
// __PRETTY_FUNCTION__ means "$FUNCTION_SIGNATURE [with T = $TYPE]".
// +2 here to skip "= "
auto const* const begin = constexpr_strchr(__PRETTY_FUNCTION__, '=') + 2;
// -2 meaning up to "]\0"
auto const size =
static_cast<std::size_t>(distance_to_end(__PRETTY_FUNCTION__, begin) - 2);
return std::string_view{begin, size};
}
// Inline string_view with the type name.
template <typename T>
inline constexpr auto type_name = type_name_finder<T>();
// Example Class
template <typename T1, typename T2>
class my_class {};
int main() {
// Example use-case
my_class<int&, std::vector<double>> my_arr[20];
std::cout << type_name<decltype(my_arr)>;
}
Code uses __PRETTY_FUNCTION__ in GCC and Clang to get a variable's type as a string. I would appreciate any comments on correctness and readability. I used a lot of GCC specific attributes, because __PRETTY_FUNCTION__ is GCC specific and for this reason the code can't be portable anyway.