Skip to content

Instantly share code, notes, and snippets.

@hidez8891
Last active November 16, 2021 11:33
Show Gist options
  • Save hidez8891/0ab5b386202d1e24c8913812c072336e to your computer and use it in GitHub Desktop.
Save hidez8891/0ab5b386202d1e24c8913812c072336e to your computer and use it in GitHub Desktop.
C++の型を文字表現化 (support C++20 later)
#include <sstream>
#include <type_traits>
#include <typeinfo>
#if __has_include(<cxxabi.h>)
#include <cxxabi.h>
inline std::string _impl_type_demangle_raw(const char* mangled)
{
int status;
char* buf = abi::__cxa_demangle(mangled, 0, 0, &status);
std::string ret { buf };
free(buf);
return ret;
}
#else
inline std::string _impl_type_demangle_raw(const char* mangled)
{
return mangled;
}
#endif
template <typename... Args>
struct _impl_type_demangle_args {
static std::string to_s();
};
template <typename A, typename... Args>
struct _impl_type_demangle_args<A, Args...> {
static std::string to_s();
};
struct _impl_type_demangle_concat {
static std::string to_s(std::string&& lhs, const char* c, std::string&& rhs)
{
if (rhs.length() != 0) {
return lhs + c + rhs;
}
return lhs;
}
};
template <typename T>
struct _impl_type_demangle {
static std::string to_s(std::string&& parent)
{
auto type = _impl_type_demangle_raw(typeid(T).name());
if (type.starts_with("struct ")) {
type = type.substr(sizeof("struct ") - 1);
}
if (type.starts_with("class ")) {
type = type.substr(sizeof("class ") - 1);
}
return _impl_type_demangle_concat::to_s(
std::move(type),
" ",
std::move(parent));
}
};
template <template <typename...> typename T, typename... Ts>
struct _impl_type_demangle<T<Ts...>> {
static std::string to_s(std::string&& parent)
{
auto type = _impl_type_demangle_raw(typeid(T<Ts...>).name());
if (type.starts_with("struct ")) {
type = type.substr(sizeof("struct ") - 1);
}
if (type.starts_with("class ")) {
type = type.substr(sizeof("class ") - 1);
}
type = type.substr(0, type.find_first_of("<"));
return _impl_type_demangle_concat::to_s(
type + "<" + _impl_type_demangle_args<Ts...>::to_s() + ">",
" ",
std::move(parent));
}
};
#define IMPL_OVERLOAD(OPT) \
template <typename T> \
struct _impl_type_demangle<T OPT> { \
static std::string to_s(std::string&& parent) \
{ \
return _impl_type_demangle<T>::to_s( \
_impl_type_demangle_concat::to_s( \
#OPT, \
" ", \
std::move(parent))); \
} \
};
// [*|&|&&]
IMPL_OVERLOAD(*)
IMPL_OVERLOAD(&)
IMPL_OVERLOAD(&&)
// [const][volatile]
IMPL_OVERLOAD(volatile)
IMPL_OVERLOAD(const)
IMPL_OVERLOAD(const volatile)
#undef IMPL_OVERLOAD
template <typename R, typename... Args>
struct _impl_type_demangle<R(Args...)> {
static std::string to_s(std::string&& parent)
{
std::stringstream ss;
ss << _impl_type_demangle<R>::to_s("") << " ";
if (parent.length() > 0) {
ss << "(" << parent << ")";
}
if (sizeof...(Args) == 0) {
ss << "(void)";
} else {
ss << "(" << _impl_type_demangle_args<Args...>::to_s() << ")";
}
return ss.str();
}
};
#define IMPL_OVERLOAD(OPT) \
template <typename R, typename... Args> \
struct _impl_type_demangle<R(Args...) OPT> { \
static std::string to_s(std::string&& parent) \
{ \
return _impl_type_demangle<R(Args...)>::to_s(std::move(parent)) + " " + #OPT; \
} \
};
// [const][volatile][&|&&][noexcept]
// clang-format off
IMPL_OVERLOAD(const volatile && noexcept)
IMPL_OVERLOAD(const volatile & noexcept)
IMPL_OVERLOAD(const volatile && )
IMPL_OVERLOAD(const volatile & )
IMPL_OVERLOAD(const volatile noexcept)
IMPL_OVERLOAD(const volatile )
IMPL_OVERLOAD(const && noexcept)
IMPL_OVERLOAD(const & noexcept)
IMPL_OVERLOAD(const && )
IMPL_OVERLOAD(const & )
IMPL_OVERLOAD(const noexcept)
IMPL_OVERLOAD(const )
IMPL_OVERLOAD( volatile && noexcept)
IMPL_OVERLOAD( volatile & noexcept)
IMPL_OVERLOAD( volatile && )
IMPL_OVERLOAD( volatile & )
IMPL_OVERLOAD( volatile noexcept)
IMPL_OVERLOAD( volatile )
IMPL_OVERLOAD( && noexcept)
IMPL_OVERLOAD( & noexcept)
IMPL_OVERLOAD( && )
IMPL_OVERLOAD( & )
IMPL_OVERLOAD( noexcept)
// clang-format on
#undef IMPL_OVERLOAD
template <typename T, typename C>
struct _impl_type_demangle<T C::*> {
static std::string to_s(std::string&& parent)
{
return _impl_type_demangle<T>::to_s(
_impl_type_demangle_concat::to_s(
_impl_type_demangle<C>::to_s("") + "::*",
" ",
std::move(parent)));
}
};
template <typename... Args>
std::string _impl_type_demangle_args<Args...>::to_s()
{
return "";
};
template <typename A, typename... Args>
std::string _impl_type_demangle_args<A, Args...>::to_s()
{
return _impl_type_demangle_concat::to_s(
_impl_type_demangle<A>::to_s(""),
", ",
_impl_type_demangle_args<Args...>::to_s());
};
template <typename T>
std::string type_demangle()
{
return _impl_type_demangle<T>::to_s("");
}
#include <gtest/gtest.h>
#include "cpp_type_demangle.hpp"
#include <string>
using namespace std::string_literals;
struct C0 {
};
template <typename T>
struct C1 {
};
template <typename T1, typename T2>
struct C2 {
};
struct CS0 {
static int valueS;
int valueI;
};
template <typename T>
struct CS1 {
static int valueS;
int valueI;
};
TEST(Test_type_demangle, variables)
{
// clang-format off
EXPECT_EQ("int"s , type_demangle<int>());
EXPECT_EQ("double"s, type_demangle<double>());
EXPECT_EQ("void"s , type_demangle<void>());
EXPECT_EQ("int const"s , type_demangle<const int>());
EXPECT_EQ("int volatile"s , type_demangle<volatile int>());
EXPECT_EQ("int const volatile"s, type_demangle<const volatile int>());
EXPECT_EQ("int *"s , type_demangle<int*>());
EXPECT_EQ("int &"s , type_demangle<int&>());
EXPECT_EQ("int &&"s, type_demangle<int&&>());
EXPECT_EQ("int * &"s , type_demangle<int*&>());
EXPECT_EQ("int * * &"s, type_demangle<int**&>());
EXPECT_EQ("int * const"s , type_demangle<int* const>());
EXPECT_EQ("int const *"s , type_demangle<int const*>());
EXPECT_EQ("int const * const"s , type_demangle<int const* const>());
EXPECT_EQ("int * const * const"s, type_demangle<int* const* const>());
// clang-format on
}
TEST(Test_type_demangle, member_variables)
{
// clang-format off
EXPECT_EQ("C0"s , type_demangle<C0>());
EXPECT_EQ("C1<int>"s , type_demangle<C1<int>>());
EXPECT_EQ("C1<int * const>"s, type_demangle<C1<int* const>>());
using type_C2 = C2<int*, double const>;
EXPECT_EQ("C2<int *, double const>"s, type_demangle<type_C2>());
EXPECT_EQ("int"s , type_demangle<decltype(CS0::valueS)>());
EXPECT_EQ("int *"s , type_demangle<decltype(&CS0::valueS)>());
EXPECT_EQ("int CS0::*"s, type_demangle<decltype(&CS0::valueI)>());
EXPECT_EQ("int"s , type_demangle<decltype(CS1<double>::valueS)>());
EXPECT_EQ("int *"s , type_demangle<decltype(&CS1<double>::valueS)>());
EXPECT_EQ("int CS1<double>::*"s, type_demangle<decltype(&CS1<double>::valueI)>());
// clang-format on
}
struct S {
static int funcS(void);
int func0(void);
int func1(int);
int func2(int, double);
// clang-format off
int funcCVRE(int) const volatile && noexcept;
int funcCVLE(int) const volatile & noexcept;
int funcCVRN(int) const volatile && ;
int funcCVLN(int) const volatile & ;
int funcCVNE(int) const volatile noexcept;
int funcCVNN(int) const volatile ;
int funcCNRE(int) const && noexcept;
int funcCNLE(int) const & noexcept;
int funcCNRN(int) const && ;
int funcCNLN(int) const & ;
int funcCNNE(int) const noexcept;
int funcCNNN(int) const ;
int funcNVRE(int) volatile && noexcept;
int funcNVLE(int) volatile & noexcept;
int funcNVRN(int) volatile && ;
int funcNVLN(int) volatile & ;
int funcNVNE(int) volatile noexcept;
int funcNVNN(int) volatile ;
int funcNNRE(int) && noexcept;
int funcNNLE(int) & noexcept;
int funcNNRN(int) && ;
int funcNNLN(int) & ;
int funcNNNE(int) noexcept;
// clang-format on
};
TEST(Test_type_demangle, functions)
{
// clang-format off
EXPECT_EQ("void (void)"s , type_demangle<void(void)>());
EXPECT_EQ("int (void)"s , type_demangle<int()>());
EXPECT_EQ("int (int)"s , type_demangle<int(int)>());
EXPECT_EQ("int (int, double)"s, type_demangle<int(int, double)>());
EXPECT_EQ("int * (void *)"s , type_demangle<int*(void*)>());
EXPECT_EQ("int * (int *, double *)"s, type_demangle<int*(int*, double*)>());
// WARNING: compiler omits the 'const' notation for arguments.
EXPECT_EQ("int (int)"s , type_demangle<int(int const)>());
EXPECT_EQ("int (int *)"s , type_demangle<int(int* const)>());
EXPECT_EQ("int (int const *)"s, type_demangle<int(int const*)>());
EXPECT_EQ("int (int) const"s , type_demangle<int(int) const >());
EXPECT_EQ("int (int) noexcept"s , type_demangle<int(int) noexcept>());
EXPECT_EQ("int (int) const noexcept"s, type_demangle<int(int) const noexcept>());
EXPECT_EQ("int (*)(int)"s, type_demangle<int (*)(int)>());
EXPECT_EQ("int (* *)(int)"s, type_demangle<int (**)(int)>());
EXPECT_EQ("int (* const)(int)"s, type_demangle<int (*const)(int)>());
// clang-format on
}
TEST(Test_type_demangle, member_functions)
{
// clang-format off
EXPECT_EQ("int (void)"s , type_demangle<decltype(S::funcS)>());
EXPECT_EQ("int (*)(void)"s, type_demangle<decltype(&S::funcS)>());
EXPECT_EQ("int (S::*)(void)"s , type_demangle<decltype(&S::func0)>());
EXPECT_EQ("int (S::*)(int)"s , type_demangle<decltype(&S::func1)>());
EXPECT_EQ("int (S::*)(int, double)"s, type_demangle<decltype(&S::func2)>());
EXPECT_EQ("int (S::*)(int) const volatile && noexcept"s, type_demangle<decltype(&S::funcCVRE)>());
EXPECT_EQ("int (S::*)(int) const volatile & noexcept"s, type_demangle<decltype(&S::funcCVLE)>());
EXPECT_EQ("int (S::*)(int) const volatile &&"s, type_demangle<decltype(&S::funcCVRN)>());
EXPECT_EQ("int (S::*)(int) const volatile &"s, type_demangle<decltype(&S::funcCVLN)>());
EXPECT_EQ("int (S::*)(int) const volatile noexcept"s, type_demangle<decltype(&S::funcCVNE)>());
EXPECT_EQ("int (S::*)(int) const volatile"s, type_demangle<decltype(&S::funcCVNN)>());
EXPECT_EQ("int (S::*)(int) const && noexcept"s, type_demangle<decltype(&S::funcCNRE)>());
EXPECT_EQ("int (S::*)(int) const & noexcept"s, type_demangle<decltype(&S::funcCNLE)>());
EXPECT_EQ("int (S::*)(int) const &&"s, type_demangle<decltype(&S::funcCNRN)>());
EXPECT_EQ("int (S::*)(int) const &"s, type_demangle<decltype(&S::funcCNLN)>());
EXPECT_EQ("int (S::*)(int) const noexcept"s, type_demangle<decltype(&S::funcCNNE)>());
EXPECT_EQ("int (S::*)(int) const"s, type_demangle<decltype(&S::funcCNNN)>());
EXPECT_EQ("int (S::*)(int) volatile && noexcept"s, type_demangle<decltype(&S::funcNVRE)>());
EXPECT_EQ("int (S::*)(int) volatile & noexcept"s, type_demangle<decltype(&S::funcNVLE)>());
EXPECT_EQ("int (S::*)(int) volatile &&"s, type_demangle<decltype(&S::funcNVRN)>());
EXPECT_EQ("int (S::*)(int) volatile &"s, type_demangle<decltype(&S::funcNVLN)>());
EXPECT_EQ("int (S::*)(int) volatile noexcept"s, type_demangle<decltype(&S::funcNVNE)>());
EXPECT_EQ("int (S::*)(int) volatile"s, type_demangle<decltype(&S::funcNVNN)>());
EXPECT_EQ("int (S::*)(int) && noexcept"s, type_demangle<decltype(&S::funcNNRE)>());
EXPECT_EQ("int (S::*)(int) & noexcept"s, type_demangle<decltype(&S::funcNNLE)>());
EXPECT_EQ("int (S::*)(int) &&"s, type_demangle<decltype(&S::funcNNRN)>());
EXPECT_EQ("int (S::*)(int) &"s, type_demangle<decltype(&S::funcNNLN)>());
EXPECT_EQ("int (S::*)(int) noexcept"s, type_demangle<decltype(&S::funcNNNE)>());
// clang-format on
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment