An alternative answer that can be used in template, now it can run with g++ and clang++ and msvc.
Modified from Answer @einpoklum above: https://stackoverflow.com/a/56600402/12529885
#include <iostream>
#include <string_view>
template<typename T>
struct TypeName {
constexpr static std::string_view fullname_intern() {
#if defined(__clang__) || defined(__GNUC__)
return __PRETTY_FUNCTION__;
#elif defined(_MSC_VER)
return __FUNCSIG__;
#else
#error "Unsupported compiler"
#endif
}
constexpr static std::string_view name() {
size_t prefix_len = TypeName<void>::fullname_intern().find("void");
size_t multiple = TypeName<void>::fullname_intern().size() - TypeName<int>::fullname_intern().size();
size_t dummy_len = TypeName<void>::fullname_intern().size() - 4*multiple;
size_t target_len = (fullname_intern().size() - dummy_len)/multiple;
std::string_view rv = fullname_intern().substr(prefix_len, target_len);
if (rv.rfind(' ') == rv.npos)
return rv;
return rv.substr(rv.rfind(' ')+1);
}
using type = T;
constexpr static std::string_view value = name();
};
namespace s1 {
class MyClass;
}
//Both MSVC, G++ and Clang++ have passed test.
int main () {
static_assert(TypeName<s1::MyClass>::value == "s1::MyClass");
std::cout<<"FULLNAME> "<<TypeName<void>::fullname_intern()<<std::endl;
std::cout<<"TYPETEST> '"<<TypeName<s1::MyClass>::value<<"' == 's1::MyClass'"<<std::endl;
return 0;
}
Note that:
Full name in Clang++: static std::string_view TypeName<void>::fullname_intern() [T = void]
Full name in G++: static constexpr std::string_view TypeName<T>::fullname_intern() [with T = void; std::string_view = std::basic_string_view<char>]
Fullname in MSVC: class std::basic_string_view<char,struct std::char_traits<char> > __cdecl TypeName<void>::fullname_intern(void)
(But 'class s1::MyClass' not 's1::MyClass' here)
type_name_length<T>
that you need it at compile time? Compilers are pretty good about just evaluatingstrlen()
and giving you a constant if that's possible. – Barry