add nameof_member

This commit is contained in:
neargye 2021-04-03 00:06:56 +03:00
parent 6df582978d
commit 2cf013dbf3
3 changed files with 86 additions and 0 deletions

View file

@ -168,6 +168,15 @@ int main() {
std::cout << NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) << std::endl; // 'const SomeClass<int> &&' std::cout << NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) << std::endl; // 'const SomeClass<int> &&'
std::cout << NAMEOF_SHORT_TYPE_EXPR(std::declval<const SomeClass<int>>()) << std::endl; // 'SomeClass' std::cout << NAMEOF_SHORT_TYPE_EXPR(std::declval<const SomeClass<int>>()) << 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. // Nameof macro.
std::cout << NAMEOF(__LINE__) << std::endl; // '__LINE__' std::cout << NAMEOF(__LINE__) << std::endl; // '__LINE__'

View file

@ -94,6 +94,12 @@
# endif # endif
#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. // Checks nameof_enum compiler compatibility.
#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910
# undef NAMEOF_ENUM_SUPPORTED # undef NAMEOF_ENUM_SUPPORTED
@ -169,6 +175,12 @@ constexpr string_view type_name() noexcept {
return {}; return {};
} }
// If need cunstom name for member, add specialization member_name for necessary type.
template <auto V>
constexpr string_view member_name() noexcept {
return {};
}
} // namespace nameof::customize } // namespace nameof::customize
template <std::size_t N> template <std::size_t N>
@ -696,6 +708,14 @@ struct nameof_type_rtti_supported
: std::false_type {}; : std::false_type {};
#endif #endif
template <typename... T>
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__) #if defined(_MSC_VER) && !defined(__clang__)
template <typename T> template <typename T>
struct identity { struct identity {
@ -829,6 +849,27 @@ string nameof_short_type_rtti(const char* tn) noexcept {
} }
#endif #endif
template <auto V>
constexpr auto n() noexcept {
constexpr auto custom_name = customize::member_name<V>();
if constexpr (custom_name.empty()) {
static_cast<void>(custom_name);
#if defined(NAMEOF_TYPE_SUPPORTED) && NAMEOF_TYPE_SUPPORTED
constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2});
return cstring<name.size()>{name};
#else
return string_view{}; // Unsupported compiler.
#endif
} else {
return cstring<custom_name.size()>{custom_name};
}
}
template <auto V>
inline constexpr auto member_name_v = n<V>();
} // namespace nameof::detail } // namespace nameof::detail
// Checks is nameof_type supported compiler. // Checks is nameof_type supported compiler.
@ -837,6 +878,9 @@ inline constexpr bool is_nameof_type_supported = detail::nameof_type_supported<v
// Checks is nameof_type_rtti supported compiler. // Checks is nameof_type_rtti supported compiler.
inline constexpr bool is_nameof_type_rtti_supported = detail::nameof_type_rtti_supported<void>::value; inline constexpr bool is_nameof_type_rtti_supported = detail::nameof_type_rtti_supported<void>::value;
// Checks is nameof_member supported compiler.
inline constexpr bool is_nameof_member_supported = detail::nameof_member_supported<void>::value;
// Checks is nameof_enum supported compiler. // Checks is nameof_enum supported compiler.
inline constexpr bool is_nameof_enum_supported = detail::nameof_enum_supported<void>::value; inline constexpr bool is_nameof_enum_supported = detail::nameof_enum_supported<void>::value;
@ -942,6 +986,16 @@ template <typename T>
return name; return name;
} }
// Obtains name of member.
template <auto V>
[[nodiscard]] constexpr auto nameof_member() noexcept -> std::enable_if_t<std::is_member_pointer_v<decltype(V)>, string_view> {
static_assert(detail::nameof_member_supported<decltype(V)>::value, "nameof::nameof_memder unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
constexpr string_view name = detail::member_name_v<V>;
static_assert(name.size() > 0, "Member does not have a name.");
return name;
}
} // namespace nameof } // namespace nameof
// Obtains name of variable, function, macro. // Obtains name of variable, function, macro.
@ -1008,6 +1062,9 @@ template <typename T>
// Obtains short type name, using RTTI. // Obtains short type name, using RTTI.
#define NAMEOF_SHORT_TYPE_RTTI(...) ::nameof::detail::nameof_short_type_rtti<decltype(__VA_ARGS__)>(typeid(__VA_ARGS__).name()) #define NAMEOF_SHORT_TYPE_RTTI(...) ::nameof::detail::nameof_short_type_rtti<decltype(__VA_ARGS__)>(typeid(__VA_ARGS__).name())
// Obtains name of member.
#define NAMEOF_MEMBER(...) ::nameof::nameof_member<__VA_ARGS__>()
#if defined(__clang__) #if defined(__clang__)
# pragma clang diagnostic pop # pragma clang diagnostic pop
#elif defined(__GNUC__) #elif defined(__GNUC__)

View file

@ -879,3 +879,23 @@ TEST_CASE("NAMEOF_SHORT_TYPE_RTTI") {
} }
#endif #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<member_ptr>() == "Derived");
}
#endif