diff --git a/example/example.cpp b/example/example.cpp index 5ed1905..fc9dc45 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -49,15 +49,16 @@ void SomeMethod3() { } template -T SomeMethod4() { - return T{}; +std::string SomeMethod4() { + std::cout << NAMEOF_TYPE_T(T) << std::endl; + return NAMEOF_FULL(SomeMethod4); } template class SomeClass { public: void SomeMethod5() const { - std::cout << NAMEOF_TYPE_T(T) << std::endl; + std::cout << nameof::NameofType() << std::endl; } template @@ -103,6 +104,7 @@ int main() { std::cout << NAMEOF(&SomeStruct::SomeMethod2) << std::endl; // SomeMethod2 std::cout << NAMEOF(SomeMethod3) << std::endl; // SomeMethod3 + std::cout << NAMEOF(SomeMethod4()) << std::endl; // SomeMethod4 std::cout << NAMEOF(SomeMethod4) << std::endl; // SomeMethod4 std::cout << NAMEOF_FULL(SomeMethod4) << std::endl; // SomeMethod4 @@ -122,11 +124,9 @@ int main() { std::cout << NAMEOF_TYPE_T(SomeClass) << std::endl; // SomeClass // Raw name. - std::cout << NAMEOF_RAW(volatile const int) << std::endl; // volatile const int std::cout << NAMEOF_RAW(__LINE__) << std::endl; // __LINE__ std::cout << NAMEOF_RAW(structvar.somefield) << std::endl; // structvar.somefield std::cout << NAMEOF_RAW(&SomeStruct::SomeMethod1) << std::endl; // &SomeStruct::SomeMethod1 - std::cout << NAMEOF_RAW(Long::LL) << std::endl; // Long::LL const auto div = [](int x, int y) -> int { if (y == 0) { @@ -143,27 +143,31 @@ int main() { } /* Remarks */ -#if 0 +#if 1 // This expression does not have a name. - std::cout << NAMEOF("Bad case") << std::endl; // '"Bad case"' - std::cout << NAMEOF("Bad case"_string) << std::endl; // '"Bad case"_string' - std::cout << NAMEOF("somevar.somefield") << std::endl; // 'somefield"' + std::cout << NAMEOF("Bad case"_string) << std::endl; // '_string' std::cout << NAMEOF(42.0) << std::endl; // '0' std::cout << NAMEOF(42.f) << std::endl; // 'f' std::cout << NAMEOF(42) << std::endl; // '42' std::cout << NAMEOF(42.0_deg) << std::endl; // '0_deg' - std::cout << NAMEOF(std::string()) << std::endl; // 'string()' - std::cout << NAMEOF(std::string{}) << std::endl; // "string{}' - std::cout << NAMEOF(std::string{"test"}) << std::endl; // 'string{"test"}' - std::cout << NAMEOF(SomeMethod4()) << std::endl; // '()' + std::cout << NAMEOF(std::string()) << std::endl; // 'string' + std::cout << NAMEOF(std::string{}) << std::endl; // 'string' + std::cout << NAMEOF(std::string{"test"}) << std::endl; // 'string' + std::cout << NAMEOF(structvar.somefield + structvar.somefield) << std::endl; // ' somefield' + std::cout << NAMEOF(42 + 42) << std::endl; // ' 42' + std::cout << NAMEOF(NAMEOF(structvar)) << std::endl; // 'NAMEOF' +#endif + +#if 0 + // This expression does not compilation. + std::cout << NAMEOF("Bad case") << std::endl; // '' + std::cout << NAMEOF("somevar.somefield") << std::endl; // '' std::cout << NAMEOF(std::basic_string) << std::endl; // '' std::cout << NAMEOF(ptrvar[0]) << std::endl; // 'ptrvar[0]' - std::cout << NAMEOF(intvar + intvar) << std::endl; // ' intvar' - std::cout << NAMEOF(NAMEOF(intvar)) << std::endl; // 'NAMEOF(intvar)' - std::cout << NAMEOF(std::cout << intvar << std::endl) << std::endl; // 'endl' - std::cout << NAMEOF(decltype(intvar)) << std::endl; // 'decltype(intvar)' - std::cout << NAMEOF(typeid(intvar)) << std::endl; // 'typeid(intvar)' - std::cout << NAMEOF((intvar)) << std::endl; // '(intvar)' + std::cout << NAMEOF(std::cout << structvar << std::endl) << std::endl; // '' + std::cout << NAMEOF(decltype(structvar)) << std::endl; // '' + std::cout << NAMEOF(typeid(structvar)) << std::endl; // '' + std::cout << NAMEOF((structvar)) << std::endl; // '' #endif return 0; diff --git a/include/nameof.hpp b/include/nameof.hpp index 88a4146..d36d45c 100644 --- a/include/nameof.hpp +++ b/include/nameof.hpp @@ -39,7 +39,7 @@ # define NAMEOF_HAS_CONSTEXPR14 1 #endif -#if defined(__clang__) || defined(_MSC_VER) +#if (defined(__clang__) || defined(_MSC_VER)) || (defined(__GNUC__) && __GNUC__ >= 5) # define NAMEOF_TYPE_CONSTEXPR constexpr # define NAMEOF_TYPE_HAS_CONSTEXPR 1 #else @@ -57,49 +57,6 @@ struct identity { using type = T; }; -template -using identity_t = typename identity::type; - -// Removes all pointer from the given type. -template -struct remove_all_p - : std::conditional::value, - remove_all_p::type>, - identity - >::type {}; - -template -using remove_all_p_t = typename remove_all_p::type; - -// Removes const, volatile, reference specifiers from the given type. -template -struct remove_cvr { - using type = typename std::remove_cv::type>::type; -}; - -template -using remove_cvr_t = typename remove_cvr::type; - -// Removes all const, volatile, reference, pointer specifiers from the given type. -template -struct remove_all_cvrp { - using type = typename remove_cvr::type>::type>::type; -}; - -template -using remove_all_cvrp_t = typename remove_all_cvrp::type; - -// Removes all const, volatile, reference, pointer, array extents specifiers from the given type. -template ::type> -struct remove_all_cvrpe - : std::conditional::value, - remove_all_cvrpe::type>, - identity - >::type {}; - -template -using remove_all_cvrpe_t = typename remove_all_cvrpe::type; - } // namespace nstd constexpr bool StrEquals(const char* lhs, const char* rhs, std::size_t size) { @@ -220,13 +177,11 @@ constexpr bool IsLexeme(char s) noexcept { constexpr cstring NameofPretty(cstring name, bool with_suffix) noexcept { std::size_t s = 0; for (std::size_t i = name.size(), h = 0; i > 0; --i) { - if (name[i - 1] == '>') { + if (name[i - 1] == '>' || name[i - 1] == ')' || name[i - 1] == '}') { ++h; ++s; continue; - } - - if (name[i - 1] == '<') { + } else if (name[i - 1] == '<' || name[i - 1] == '(' || name[i - 1] == '{') { --h; ++s; continue; @@ -249,31 +204,32 @@ constexpr cstring NameofPretty(cstring name, bool with_suffix) noexcept { return name.remove_suffix(with_suffix ? 0 : s); } #else -constexpr std::size_t NameofBaseImpl1(cstring name, std::size_t h = 0, std::size_t s = 0) noexcept { - return name[name.size() - 1 - s] == '>' - ? NameofBaseImpl1(name, h + 1, s + 1) - : name[name.size() - 1 - s] == '<' - ? NameofBaseImpl1(name, h - 1, s + 1) - : h == 0 ? s : NameofBaseImpl1(name, h, s + 1); +constexpr std::size_t FindSuffix(cstring name, std::size_t h = 0, std::size_t s = 0) noexcept { + return (name[name.size() - 1 - s] == '>' || name[name.size() - 1 - s] == ')' || name[name.size() - 1 - s] == '}') + ? FindSuffix(name, h + 1, s + 1) + : (name[name.size() - 1 - s] == '<' || name[name.size() - 1 - s] == ')' || name[name.size() - 1 - s] == '{') + ? FindSuffix(name, h - 1, s + 1) + : h == 0 ? s : FindSuffix(name, h, s + 1); } -constexpr cstring NameofBaseImpl2(cstring name, const std::size_t p = 0) noexcept { +constexpr cstring RemovePrefix(cstring name, const std::size_t p = 0) noexcept { return p == name.size() ? name : IsLexeme(name[name.size() - 1 - p]) ? name.remove_prefix(name.size() - p) - : NameofBaseImpl2(name, p + 1); + : RemovePrefix(name, p + 1); } -constexpr cstring NameofBaseImpl3(cstring name, std::size_t s, bool with_suffix) noexcept { - return NameofBaseImpl2(name.remove_suffix(s)).add_suffix(with_suffix ? s : 0); +constexpr cstring NameofPrettyImpl(cstring name, std::size_t s, bool with_suffix) noexcept { + return RemovePrefix(name.remove_suffix(s)).add_suffix(with_suffix ? s : 0); } constexpr cstring NameofPretty(cstring name, bool with_suffix) noexcept { - return NameofBaseImpl3(name, NameofBaseImpl1(name), with_suffix); + return NameofPrettyImpl(name, FindSuffix(name), with_suffix); } #endif -constexpr cstring RemoveSpace(cstring name) noexcept { - return name.back() == ' ' ? RemoveSpace(name.remove_suffix(1)) : name; +#if defined(_MSC_VER) +constexpr cstring RemoveSpaceSuffix(cstring name) noexcept { + return name.back() == ' ' ? RemoveSpaceSuffix(name.remove_suffix(1)) : name; } constexpr cstring RemoveClassPrefix(cstring name) noexcept { @@ -297,27 +253,39 @@ constexpr cstring RemoveStructPrefix(cstring name) noexcept { : name; } -constexpr cstring NameofTypeRawPretty(cstring name) noexcept { - return RemoveClassPrefix(RemoveStructPrefix(RemoveEnumPrefix(RemoveSpace(name)))); +constexpr cstring NameofTypePretty(cstring name) noexcept { + return RemoveClassPrefix(RemoveStructPrefix(RemoveEnumPrefix(RemoveSpaceSuffix(name)))); } +#elif defined(__clang__) || defined(__GNUC__) +constexpr cstring NameofTypePretty(const char* str, std::size_t size, std::size_t prefix, std::size_t suffix) noexcept { + return {str, size, prefix, suffix + (str[size - suffix - 1] == ' ' ? 1 : 0)}; +} +#endif template -NAMEOF_TYPE_CONSTEXPR cstring NameofTypeRaw() noexcept { +NAMEOF_TYPE_CONSTEXPR cstring NameofType() noexcept { #if defined(__clang__) - return {__PRETTY_FUNCTION__, - sizeof(__PRETTY_FUNCTION__) - 1, - sizeof("nameof::detail::cstring nameof::detail::NameofTypeRaw() [T = nameof::detail::nstd::identity<") - 1, - sizeof(">]") - 1}; + return NameofTypePretty( + __PRETTY_FUNCTION__, + sizeof(__PRETTY_FUNCTION__) - 1, + sizeof("nameof::detail::cstring nameof::detail::NameofType() [T = nameof::detail::nstd::identity<") - 1, + sizeof(">]") - 1); #elif defined(__GNUC__) - return {__PRETTY_FUNCTION__, - sizeof(__PRETTY_FUNCTION__) - 1, - sizeof("nameof::detail::cstring nameof::detail::NameofTypeRaw() [with T = nameof::detail::nstd::identity<") - 1, - sizeof(">]") - 1}; + return NameofTypePretty( + __PRETTY_FUNCTION__, + sizeof(__PRETTY_FUNCTION__) - 1, +# if defined(NAMEOF_TYPE_HAS_CONSTEXPR) + sizeof("constexpr nameof::detail::cstring nameof::detail::NameofType() [with T = nameof::detail::nstd::identity<") - 1, +# else + sizeof("nameof::detail::cstring nameof::detail::NameofType() [with T = nameof::detail::nstd::identity<") - 1, +# endif + sizeof(">]") - 1); #elif defined(_MSC_VER) - return {__FUNCSIG__, - sizeof(__FUNCSIG__) - 1, - sizeof("class nameof::detail::cstring __cdecl nameof::detail::NameofTypeRaw>(void) noexcept") - 1}; + return NameofTypePretty( + {__FUNCSIG__, + sizeof(__FUNCSIG__) - 1, + sizeof("class nameof::detail::cstring __cdecl nameof::detail::NameofType>(void) noexcept") - 1}); #else return {}; #endif @@ -326,16 +294,11 @@ NAMEOF_TYPE_CONSTEXPR cstring NameofTypeRaw() noexcept { template ::value && !std::is_void::value>::type> -constexpr cstring Nameof(const T&, const char* name, std::size_t size, bool with_suffix) noexcept { +constexpr cstring Nameof(const char* name, std::size_t size, bool with_suffix) noexcept { return NameofPretty({name, size}, with_suffix); } -template ::value && - !std::is_function::value && - !std::is_member_function_pointer::value>::type> -constexpr cstring Nameof(T&&, const char*, std::size_t, bool) = delete; - +template constexpr cstring NameofRaw(const char* name, std::size_t size) noexcept { return {name, size}; } @@ -343,42 +306,21 @@ constexpr cstring NameofRaw(const char* name, std::size_t size) noexcept { } // namespace detail template > -NAMEOF_TYPE_CONSTEXPR detail::cstring NameofType(bool pretty = true) noexcept { - return pretty ? detail::NameofTypeRawPretty(detail::NameofTypeRaw()) : detail::NameofTypeRaw(); +NAMEOF_TYPE_CONSTEXPR detail::cstring NameofType() noexcept { + return true ? detail::NameofType() : detail::NameofType(); } } // namespace nameof -#if defined(__clang__) -# if __has_feature(cxx_rtti) -# define NAMEOF_HAS_RTTI 1 -# endif -#elif defined(__GNUC__) -# if defined(__GXX_RTTI) -# define NAMEOF_HAS_RTTI 1 -# endif -#elif defined(_MSC_VER) && defined(_CPPRTTI) -# if defined(_CPPRTTI) -# define NAMEOF_HAS_RTTI 1 -# endif -#endif +// Used to obtain the simple (unqualified) string name of a variable, member, function, macros. +#define NAMEOF(name) ::nameof::detail::Nameof(#name, (sizeof(#name) / sizeof(char)) - 1, false) -#if defined(NAMEOF_HAS_RTTI) || defined(_MSC_VER) -#include +// Used to obtain the full string name of a variable, member, function, macros. +#define NAMEOF_FULL(name) ::nameof::detail::Nameof(#name, (sizeof(#name) / sizeof(char)) - 1, true) -// Used to obtain the raw string name of a variable, type, member, function, macros. -# define NAMEOF_RAW(name) ::nameof::detail::NameofRaw(#name, ((sizeof(#name) / sizeof(char)) - 1) + (0 * sizeof(typeid(name)))) -#elif defined(__clang__) || defined(__GNUC__) -// Used to obtain the raw string name of a variable, type, member, function, macros. -# define NAMEOF_RAW(name) ::nameof::detail::NameofRaw(#name, ((sizeof(#name) / sizeof(char)) - 1) + (0 * sizeof(void(*)(__typeof__(name))))) -#endif - -// Used to obtain the simple (unqualified) string name of a variable, member, function. -#define NAMEOF(name) ::nameof::detail::Nameof(name, #name, (sizeof(#name) / sizeof(char)) - 1, false) - -// Used to obtain the full string name of a variable, member, function. -#define NAMEOF_FULL(name) ::nameof::detail::Nameof(name, #name, (sizeof(#name) / sizeof(char)) - 1, true) +// Used to obtain the raw string name of a variable, member, function, macros. +#define NAMEOF_RAW(name) ::nameof::detail::NameofRaw(#name, (sizeof(#name) / sizeof(char)) - 1) // Used to obtain the string name of a type. -#define NAMEOF_TYPE(var) ::nameof::NameofType(true) -#define NAMEOF_TYPE_T(type) ::nameof::NameofType(true) +#define NAMEOF_TYPE(var) ::nameof::NameofType() +#define NAMEOF_TYPE_T(type) ::nameof::NameofType() diff --git a/test/test.cpp b/test/test.cpp index b61caab..0de16d8 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -114,9 +114,6 @@ TEST_CASE("constexpr") { // member constexpr auto cx2 = NAMEOF_RAW((&structvar)->somefield); static_assert(cx2 == "(&structvar)->somefield", ""); - // type - constexpr auto cx3 = NAMEOF_RAW(std::string); - static_assert(cx3 == "std::string", ""); // function constexpr auto cx4 = NAMEOF_RAW(&SomeStruct::SomeMethod2); static_assert(cx4 == "&SomeStruct::SomeMethod2", ""); @@ -127,24 +124,23 @@ TEST_CASE("constexpr") { constexpr auto cx6 = NAMEOF_RAW(__cplusplus); static_assert(cx6 == "__cplusplus", ""); } - - // constexpr NAMEOF_TYPE not supported in GCC. -#if defined(_MSC_VER) || defined(__clang__) +#if defined(NAMEOF_TYPE_HAS_CONSTEXPR) SECTION("NAMEOF_TYPE") { constexpr auto cx = NAMEOF_TYPE(classvar); -#if defined(__clang__) +# if defined(__clang__) static_assert(cx == "const volatile SomeClass *", ""); -#elif defined(_MSC_VER) +# elif defined(_MSC_VER) static_assert(cx == "SomeClass const volatile *", ""); -#endif +# endif } + SECTION("NAMEOF_TYPE_T") { constexpr auto cx = NAMEOF_TYPE_T(const SomeClass volatile *); -#if defined(__clang__) +# if defined(__clang__) static_assert(cx == "const volatile SomeClass *", ""); -#elif defined(_MSC_VER) +# elif defined(_MSC_VER) static_assert(cx == "SomeClass const volatile *", ""); -#endif +# endif } #endif } @@ -225,16 +221,6 @@ TEST_CASE("NAMEOF_RAW") { REQUIRE(NAMEOF_RAW(othervar.ll.field) == "othervar.ll.field"); } - SECTION("type") { - REQUIRE(NAMEOF_RAW(int[]) == "int[]"); - REQUIRE(NAMEOF_RAW(int) == "int"); - REQUIRE(NAMEOF_RAW(const volatile int[]) == "const volatile int[]"); - REQUIRE(NAMEOF_RAW(std::string) == "std::string"); - REQUIRE(NAMEOF_RAW(SomeStruct) == "SomeStruct"); - REQUIRE(NAMEOF_RAW(Long::LL) == "Long::LL"); - REQUIRE(NAMEOF_RAW(Color) == "Color"); - } - SECTION("function") { REQUIRE(NAMEOF_RAW(&SomeStruct::SomeMethod1) == "&SomeStruct::SomeMethod1"); REQUIRE(NAMEOF_RAW(&SomeStruct::SomeMethod2) == "&SomeStruct::SomeMethod2");