From 2cf013dbf30b8d38f26550a5bfc63b4833a77e5a Mon Sep 17 00:00:00 2001 From: neargye Date: Sat, 3 Apr 2021 00:06:56 +0300 Subject: [PATCH] add nameof_member --- example/example.cpp | 9 +++++++ include/nameof.hpp | 57 +++++++++++++++++++++++++++++++++++++++++++++ test/test.cpp | 20 ++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/example/example.cpp b/example/example.cpp index eb2f106..5f4aa75 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -168,6 +168,15 @@ int main() { std::cout << NAMEOF_FULL_TYPE_EXPR(std::declval>()) << std::endl; // 'const SomeClass &&' std::cout << NAMEOF_SHORT_TYPE_EXPR(std::declval>()) << std::endl; // 'SomeClass' +#if defined(NAMEOF_MEMBER_SUPPORTED) + // Nameof member + std::cout << nameof::nameof_member<&SomeStruct::somefield>() << std::endl; // somefield + std::cout << nameof::nameof_member<&SomeStruct::SomeMethod1>() << std::endl; // SomeMethod1 + std::cout << NAMEOF_MEMBER(&Long::LL::field) << std::endl; // field + constexpr auto member_ptr = &SomeStruct.somefield; + std::cout << NAMEOF_MEMBER(member_ptr) << std::endl; // field +#endif + // Nameof macro. std::cout << NAMEOF(__LINE__) << std::endl; // '__LINE__' diff --git a/include/nameof.hpp b/include/nameof.hpp index b6e66b7..de63310 100644 --- a/include/nameof.hpp +++ b/include/nameof.hpp @@ -94,6 +94,12 @@ # endif #endif +// Checks nameof_member compiler compatibility. +#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 7 +# undef NAMEOF_MEMBER_SUPPORTED +# define NAMEOF_MEMBER_SUPPORTED 1 +#endif + // Checks nameof_enum compiler compatibility. #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 # undef NAMEOF_ENUM_SUPPORTED @@ -169,6 +175,12 @@ constexpr string_view type_name() noexcept { return {}; } +// If need cunstom name for member, add specialization member_name for necessary type. +template +constexpr string_view member_name() noexcept { + return {}; +} + } // namespace nameof::customize template @@ -696,6 +708,14 @@ struct nameof_type_rtti_supported : std::false_type {}; #endif +template +struct nameof_member_supported +#if defined(NAMEOF_MEMBER_SUPPORTED) && NAMEOF_MEMBER_SUPPORTED || defined(NAMEOF_TYPE_NO_CHECK_SUPPORT) + : std::true_type {}; +#else + : std::false_type {}; +#endif + #if defined(_MSC_VER) && !defined(__clang__) template struct identity { @@ -829,6 +849,27 @@ string nameof_short_type_rtti(const char* tn) noexcept { } #endif +template +constexpr auto n() noexcept { + constexpr auto custom_name = customize::member_name(); + + if constexpr (custom_name.empty()) { + static_cast(custom_name); +#if defined(NAMEOF_TYPE_SUPPORTED) && NAMEOF_TYPE_SUPPORTED + constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2}); + + return cstring{name}; +#else + return string_view{}; // Unsupported compiler. +#endif + } else { + return cstring{custom_name}; + } +} + +template +inline constexpr auto member_name_v = n(); + } // namespace nameof::detail // Checks is nameof_type supported compiler. @@ -837,6 +878,9 @@ inline constexpr bool is_nameof_type_supported = detail::nameof_type_supported::value; +// Checks is nameof_member supported compiler. +inline constexpr bool is_nameof_member_supported = detail::nameof_member_supported::value; + // Checks is nameof_enum supported compiler. inline constexpr bool is_nameof_enum_supported = detail::nameof_enum_supported::value; @@ -942,6 +986,16 @@ template return name; } +// Obtains name of member. +template +[[nodiscard]] constexpr auto nameof_member() noexcept -> std::enable_if_t, string_view> { + static_assert(detail::nameof_member_supported::value, "nameof::nameof_memder unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility)."); + constexpr string_view name = detail::member_name_v; + static_assert(name.size() > 0, "Member does not have a name."); + + return name; +} + } // namespace nameof // Obtains name of variable, function, macro. @@ -1008,6 +1062,9 @@ template // Obtains short type name, using RTTI. #define NAMEOF_SHORT_TYPE_RTTI(...) ::nameof::detail::nameof_short_type_rtti(typeid(__VA_ARGS__).name()) +// Obtains name of member. +#define NAMEOF_MEMBER(...) ::nameof::nameof_member<__VA_ARGS__>() + #if defined(__clang__) # pragma clang diagnostic pop #elif defined(__GNUC__) diff --git a/test/test.cpp b/test/test.cpp index 41530b7..b40cb69 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -879,3 +879,23 @@ TEST_CASE("NAMEOF_SHORT_TYPE_RTTI") { } #endif + +#if defined(NAMEOF_MEMBER_SUPPORTED) && NAMEOF_MEMBER_SUPPORTED + +TEST_CASE("NAMEOF_MEMBER") { + REQUIRE(NAMEOF_MEMBER(&SomeStruct::somefield) == "Derived"); + REQUIRE(NAMEOF_MEMBER(&SomeStruct::SomeMethod1) == "Derived"); + REQUIRE(NAMEOF_MEMBER(&Long::LL::field) == "Derived"); + constexpr auto member_ptr = &SomeStruct.somefield; + REQUIRE(NAMEOF_MEMBER(member_ptr) == "Derived"); +} + +TEST_CASE("nameof_member") { + REQUIRE(nameof::nameof_member<&SomeStruct::somefield>() == "Derived"); + REQUIRE(nameof::nameof_member<&SomeStruct::SomeMethod1>() == "Derived"); + REQUIRE(nameof::nameof_member<&Long::LL::field>() == "Derived"); + constexpr auto member_ptr = &SomeStruct.somefield; + REQUIRE(nameof::nameof_member() == "Derived"); +} + +#endif