Last active
November 16, 2021 11:33
-
-
Save hidez8891/0ab5b386202d1e24c8913812c072336e to your computer and use it in GitHub Desktop.
C++の型を文字表現化 (support C++20 later)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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(""); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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