Quantcast
Channel: User HolyBlackCat - Stack Overflow
Viewing all articles
Browse latest Browse all 1287

Answer by HolyBlackCat for C++ Get name of type in template

$
0
0

This trick was mentioned under a few other questions, but not here yet.

All major compilers support __PRETTY_FUNC__ (GCC & Clang) /__FUNCSIG__ (MSVC) as an extension.

When used in a template like this:

template <typename T> const char *foo(){    #ifdef _MSC_VER    return __FUNCSIG__;    #else    return __PRETTY_FUNCTION__;    #endif}

It produces strings in a compiler-dependent format, that contain, among other things, the name of T.

E.g. foo<float>() returns:

  • "const char* foo() [with T = float]" on GCC
  • "const char *foo() [T = float]" on Clang
  • "const char *__cdecl foo<float>(void)" on MSVC

You can easily parse the type names out of those strings. You just need to figure out how many 'junk' characters your compiler inserts before and after the type.

You can even do that completely at compile-time.


The resulting names can slightly vary between different compilers. E.g. Clang omits default template arguments, and MSVC adds prefixes class/struct/union/enum to the respective types.


Here's an implementation that I've been using. Everything is done at compile-time.

Example usage:

std::cout << TypeName<float>() << '\n';std::cout << TypeName<decltype(1.2f)>(); << '\n';

Implementation: (uses C++20, but can be backported; see the edit history for a C++17 version)

#include <algorithm>#include <array>#include <cstddef>#include <string_view>namespace impl{    template <typename T>    [[nodiscard]] constexpr std::string_view RawTypeName()    {        #ifndef _MSC_VER        return __PRETTY_FUNCTION__;        #else        return __FUNCSIG__;        #endif    }    struct TypeNameFormat    {        std::size_t junk_leading = 0;        std::size_t junk_total = 0;    };    constexpr TypeNameFormat type_name_format = []{        TypeNameFormat ret;        std::string_view sample = RawTypeName<int>();        ret.junk_leading = sample.find("int");        ret.junk_total = sample.size() - 3;        return ret;    }();    static_assert(type_name_format.junk_leading != std::size_t(-1), "Unable to determine the type name format on this compiler.");    template <typename T>    static constexpr auto type_name_storage = []{        std::array<char, RawTypeName<T>().size() - type_name_format.junk_total + 1> ret{};        std::copy_n(RawTypeName<T>().data() + type_name_format.junk_leading, ret.size() - 1, ret.data());        return ret;    }();}template <typename T>[[nodiscard]] constexpr std::string_view TypeName(){    return {impl::type_name_storage<T>.data(), impl::type_name_storage<T>.size() - 1};}template <typename T>[[nodiscard]] constexpr const char *TypeNameCstr(){    return impl::type_name_storage<T>.data();}

Viewing all articles
Browse latest Browse all 1287

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>