Last active
October 13, 2015 02:18
-
-
Save eral/4123759 to your computer and use it in GitHub Desktop.
typenameof
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
//https://gist.github.com/eral/4123759 | |
#if defined(__INTEL_COMPILER) | |
# include <cstring> | |
#endif | |
#if defined(__GNUC__) | |
# include <cxxabi.h> | |
#endif | |
#include <string> | |
#include <utility> | |
#include <iterator> | |
#include <algorithm> | |
#include <iostream> | |
#include <typeinfo> | |
#include <cstddef> | |
#if (0 < _MSC_VER) | |
//VC++ 2012 2010 2008 2005 | |
//const char *__cdecl utility::detail::typenameof_::typenameof<int>(int *) | |
# define UTILITY_TYPENAMEOF_ANALYZE_DIRECT_INSERTION | |
#elif defined(__INTEL_COMPILER) | |
//ICC 13.0.1 | |
//const char *utility::detail::typenameof_::typenameof(T *) [with T = int] | |
# define UTILITY_TYPENAMEOF_ANALYZE_NOTE_ARGUMENT_ONLY | |
#elif defined(__clang__) | |
# if ((4 <= __clang_major__) || ((3 == __clang_major__) && (1 <= __clang_minor__))) | |
//Clang 3.2 3.1 | |
//const char *utility::detail::typenameof_::typenameof(T *) [T = int] | |
# define UTILITY_TYPENAMEOF_ANALYZE_NOTE_ARGUMENT_ONLY | |
# else | |
//Clang 3.0 | |
//const char *utility::detail::typenameof_::typenameof(int *) | |
# define UTILITY_TYPENAMEOF_ANALYZE_DIRECT_INSERTION | |
# endif | |
#elif defined(__GNUC__) | |
//GCC 4.8.0 4.7.2 4.6.3 4.5.3 4.4.7 | |
//const char *utility::detail::typenameof_::typenameof(T*) [with T = int] | |
# define UTILITY_TYPENAMEOF_ANALYZE_NOTE_ARGUMENT_ONLY | |
#endif | |
#if (0 < _MSC_VER) | |
# define UTILITY_TYPENAMEOF_PRETTY_FUNCTION __FUNCSIG__ | |
#else | |
# define UTILITY_TYPENAMEOF_PRETTY_FUNCTION __PRETTY_FUNCTION__ | |
#endif | |
namespace utility { | |
namespace detail { namespace typenameof_ { | |
template <typename T> | |
struct range { | |
T begin; | |
T end; | |
range(T be, T en): begin(be), end(en) {} | |
}; | |
template <std::size_t N> | |
class string : private string<N-1> { | |
typedef string<N-1> super_type; | |
char m_value; | |
protected: | |
string(const char *begin, const char *end): super_type(begin, end), m_value((begin+N-1 < end)? begin[N-1]: '\0') {} | |
public: | |
const char *get() { | |
return reinterpret_cast<const char *>(this); | |
} | |
string(const range<const char *> &src): super_type(src.begin, src.end), m_value('\0') {} | |
}; | |
template <> | |
class string<0> { | |
protected: | |
string(const char *, const char *) {} | |
public: | |
}; | |
range<const char *> analyze(const char *begin, const char *end, char begin_mark, std::size_t begin_ofst, char end_mark, std::size_t end_ofst) { | |
return range<const char *>(&*(std::find(begin, end, begin_mark) + begin_ofst) | |
, &*std::find(std::reverse_iterator<const char *>(end) | |
, std::reverse_iterator<const char *>(begin) | |
, end_mark | |
) + end_ofst | |
); | |
} | |
#if defined(UTILITY_TYPENAMEOF_ANALYZE_DIRECT_INSERTION) | |
template<std::size_t N> | |
range<const char *> analyze(const char (&pretty_function)[N]) { | |
return analyze(pretty_function, pretty_function + N, '(', 1, '*', 0); | |
} | |
#elif defined(UTILITY_TYPENAMEOF_ANALYZE_NOTE_ARGUMENT_ONLY) | |
# if defined(__INTEL_COMPILER) | |
range<const char *> analyze(const char *pretty_function) { | |
std::size_t N = std::strlen(pretty_function) + 1; | |
return analyze(pretty_function, pretty_function + N, '=', 2, ']', 0); | |
} | |
# else | |
template<std::size_t N> | |
range<const char *> analyze(const char (&pretty_function)[N]) { | |
return analyze(pretty_function, pretty_function + N, '=', 2, ']', 0); | |
} | |
# endif | |
#else | |
range<const char *> analyze(const char *pretty_function) { | |
std::size_t N = std::strlen(pretty_function) + 1; | |
return range(pretty_function, pretty_function + N); | |
} | |
#endif | |
template <typename T> | |
const char *typenameof(T*) { | |
#if defined(__INTEL_COMPILER) | |
range<const char *> typename_range = analyze(UTILITY_TYPENAMEOF_PRETTY_FUNCTION); | |
static std::string typename_string(typename_range.begin, typename_range.end); | |
return typename_string.c_str(); | |
#else | |
range<const char *> typename_range = analyze(UTILITY_TYPENAMEOF_PRETTY_FUNCTION); | |
static string<sizeof(UTILITY_TYPENAMEOF_PRETTY_FUNCTION)> typename_string(typename_range); | |
return typename_string.get(); | |
#endif | |
} | |
}} | |
template <typename T> | |
const char *typenameof() { | |
return detail::typenameof_::typenameof<T>(0); | |
} | |
template <typename T> | |
const char *typenameof(const T &) { | |
return detail::typenameof_::typenameof<T>(0); | |
} | |
} | |
#undef UTILITY_TYPENAMEOF_ANALYZE_DIRECT_INSERTION | |
#undef UTILITY_TYPENAMEOF_ANALYZE_NOTE_ARGUMENT_ONLY | |
#undef UTILITY_TYPENAMEOF_PRETTY_FUNCTION | |
#if (0 < _MSC_VER) | |
std::string demangle(const std::string &src) { | |
return src; | |
} | |
#elif defined(__GNUC__) | |
std::string demangle(const std::string &src) { | |
int status; | |
char *buf = abi::__cxa_demangle(src.c_str(), 0, 0, &status); | |
std::string result(buf); | |
free(buf); | |
return result; | |
} | |
#else | |
std::string demangle(const std::string &src) { | |
return src; | |
} | |
#endif | |
namespace hage { namespace hige { | |
template <typename T> | |
class huge { | |
public: | |
class hege { | |
public: | |
template <typename U> | |
struct hoge { | |
void test() { | |
std::cout << "|`::utility::typenameof()` |`\"" << ::utility::typenameof(this) << "\"`|" << std::endl; | |
std::cout << "|`demangle(type_info::name())`|`\"" << demangle(typeid(this).name()) << "\"`|" << std::endl; | |
} | |
}; | |
}; | |
}; | |
}} | |
int main(void) | |
{ | |
std::cout << "|`::utility::typenameof<>` |`\"" << ::utility::typenameof<int>() << "\"`|" << std::endl; | |
std::cout << "|`demangle(type_info::name())`|`\"" << demangle(typeid(int).name()) << "\"`|" << std::endl; | |
{ | |
typedef ::std::pair<int *, long> test_type; | |
test_type instance; | |
std::cout << "|`::utility::typenameof()` |`\"" << ::utility::typenameof(instance) << "\"`|" << std::endl; | |
std::cout << "|`demangle(type_info::name())`|`\"" << demangle(typeid(test_type()).name()) << "\"`|" << std::endl; | |
} | |
{ | |
typedef ::hage::hige::huge< ::std::size_t *>::hege::hoge< ::std::pair<int *, long> > test_type; | |
std::cout << "|`::utility::typenameof<>` |`\"" << ::utility::typenameof<test_type>() << "\"`|" << std::endl; | |
std::cout << "|`demangle(type_info::name())`|`\"" << demangle(typeid(test_type).name()) << "\"`|" << std::endl; | |
test_type instance; | |
instance.test(); | |
} | |
return 0; | |
} |
C++03版はこんな感じだと思う。
クラス名のみを所得するはずだったけど、予定変更してtype_info::name()
と同じ文字列の取得を目指す。
Visual Studio 2008 | int |
---|---|
::utility::typenameof |
"int " |
type_info::name() |
"int" |
Visual Studio 2008 | struct std::pair<int *,long> |
---|---|
::utility::typenameof |
"struct std::pair<int *,long> " |
type_info::name() |
"struct std::pair<int *,long>" |
Visual Studio 2008 | struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> > |
---|---|
::utility::typenameof |
"struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> > " |
type_info::name() |
"struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> >" |
Visual Studio 2008 | struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> > * |
---|---|
::utility::typenameof |
"struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> > *" |
type_info::name() |
"struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> > *" |
最後に空白が乗る事があるけど、取り敢えずVS2008は問題無し。
GCC 4.3.4 | int |
---|---|
::utility::typenameof |
"int" |
type_info::name() |
"i" |
GCC 4.3.4 | struct std::pair<int *,long> |
---|---|
::utility::typenameof |
"std::pair<int*, long int>" |
type_info::name() |
"St4pairIPilE" |
GCC 4.3.4 | struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> > |
---|---|
::utility::typenameof |
"hage::hige::huge<size_t*>::hege::hoge<std::pair<int*, long int> >" |
type_info::name() |
"N4hage4hige4hugeIPjE4hege4hogeISt4pairIPilEEE" |
GCC 4.3.4 | struct hage::hige::huge<unsigned int *>::hege::hoge<struct std::pair<int *,long> > * |
---|---|
::utility::typenameof |
"hage::hige::huge<size_t*>::hege::hoge<std::pair<int*, long int> >*" |
type_info::name() |
"PN4hage4hige4hugeIPjE4hege4hogeISt4pairIPilEEE" |
そう言えばtype_info::name()
の値って特に決まってないのでしたね。
GCC の type_info::name() はabi::__cxa_demangle 後の値を目標しよう。
コンパイラ | バージョン |
---|---|
Visual Studio | 2012, 2010, 2008, 2005 |
Gcc | 4.8, 4.7, 4.6, 4.5, 4.4 |
Clang | 3.2, 3.1 |
上記は取り敢えず妥当な値が返ってくる。
ICC 13.0 に取り敢えず対応。
コンパイルタイム時に文字長が取れないのでstd::strlen
を使っています。
関数シグネチャ用確認コード
#include <string>
#include <iostream>
namespace utility {
namespace detail {
namespace typenameof_ {
template <typename T>
std::string typenameof(T*) {
#if (0 < _MSC_VER)
return __FUNCSIG__;
#else
return __PRETTY_FUNCTION__;
#endif
}
}
}
template <typename T>
std::string typenameof() {
return detail::typenameof_::typenameof<T>(0);
}
template <typename T>
std::string typenameof(const T &) {
return detail::typenameof_::typenameof<T>(0);
}
}
int main(void)
{
std::cout << ::utility::typenameof<int>() << std::endl;
std::cout << ::utility::typenameof(0) << std::endl;
return 0;
}
GCC | __PRETTY_FUNCTION__ |
---|---|
GCC 4.8.0 | std::string utility::detail::typenameof_::typenameof(T*) [with T = int; std::string = std::basic_string<char>] |
GCC 4.7.2 | ↑ |
GCC 4.6.3 | std::string utility::detail::typenameof_::typenameof(T*) [with T = int, std::string = std::basic_string<char>] |
GCC 4.5.x | ↑ |
GCC 4.4.x | std::string utility::detail::typenameof_::typenameof(T*) [with T = int] |
Clang | __PRETTY_FUNCTION__ |
---|---|
Clang 3.2.x | std::string utility::detail::typenameof_::typenameof(T *) [T = int] |
Clang 3.1.x | ↑ |
Clang 3.0.x | std::string utility::detail::typenameof_::typenameof(int *) |
ICC | __PRETTY_FUNCTION__ |
---|---|
ICC 13.0.1 | std::basic_string<char, std::char_traits<char>, std::allocator<char>> utility::detail::typenameof_::typenameof(T *) [with T = int] |
VC++ | __FUNCSIG__ |
---|---|
VC++ 2012 | class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl utility::detail::typenameof_::typenameof<int>(int *) |
VC++ 2010 | ↑ |
VC++ 2008 | ↑ |
VC++ 2005 | ↑ |
関数シグネチャ用確認コード(not std::string version)
#include <iostream>
namespace utility {
namespace detail {
namespace typenameof_ {
template <typename T>
const char *typenameof(T*) {
#if (0 < _MSC_VER)
return __FUNCSIG__;
#else
return __PRETTY_FUNCTION__;
#endif
}
}
}
template <typename T>
const char *typenameof() {
return detail::typenameof_::typenameof<T>(0);
}
template <typename T>
const char *typenameof(const T &) {
return detail::typenameof_::typenameof<T>(0);
}
}
int main(void)
{
std::cout << ::utility::typenameof<int>() << std::endl;
std::cout << ::utility::typenameof(0) << std::endl;
return 0;
}
GCC | __PRETTY_FUNCTION__ |
---|---|
GCC 4.8.0 | const char *utility::detail::typenameof_::typenameof(T*) [with T = int] |
GCC 4.7.2 | ↑ |
GCC 4.6.3 | ↑ |
GCC 4.5.x | ↑ |
GCC 4.4.x | ↑ |
Clang | __PRETTY_FUNCTION__ |
---|---|
Clang 3.2.x | const char *utility::detail::typenameof_::typenameof(T *) [T = int] |
Clang 3.1.x | ↑ |
Clang 3.0.x | const char *utility::detail::typenameof_::typenameof(int *) |
ICC | __PRETTY_FUNCTION__ |
---|---|
ICC 13.0.1 | const char *utility::detail::typenameof_::typenameof(T *) [with T = int] |
VC++ | __FUNCSIG__ |
---|---|
VC++ 2012 | const char *__cdecl utility::detail::typenameof_::typenameof<int>(int *) |
VC++ 2010 | ↑ |
VC++ 2008 | ↑ |
VC++ 2005 | ↑ |
戻り値をstd::string
からconst char *
に変更。
これに伴いTMPにて文字長が取得出来無いICCに於いて、関数内static変数てにメモリアロケートが走ると言う酷い構成に為りました。
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
初版