Last active
May 14, 2024 18:58
-
-
Save schaumb/d036ab04df35550866577edea51f7f10 to your computer and use it in GitHub Desktop.
c++ get member name from member pointer
This file contains hidden or 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
// see at godbolt : https://godbolt.org/z/zMGEGs99v | |
#include <string_view> | |
template<auto V> | |
constexpr static auto n() noexcept { | |
#ifdef _MSC_VER | |
std::string_view sv = __FUNCSIG__; | |
auto to = sv.rfind('>')-1; | |
for (std::size_t close = sv[to] == ')'; close > 0; ) { | |
switch(sv[to = sv.find_last_of(")(", to-1)]) { | |
case ')': ++close; break; | |
case '(': if (!--close) --to; break; | |
} | |
} | |
for (std::size_t close = sv[to] == '>'; close > 0; ) { | |
switch(sv[to = sv.find_last_of("><", to-1)]) { | |
case '>': ++close; break; | |
case '<': if (!--close) --to; break; | |
} | |
} | |
auto from = sv.find_last_of(">:", to); | |
return sv.substr(from + 1, to - from); | |
#else | |
std::string_view sv = __PRETTY_FUNCTION__; | |
auto from = sv.rfind(':'); | |
return sv.substr(from + 1, sv.size() - 2 - from); | |
#endif | |
} | |
template<class From, class Type> | |
From get_base_type(Type From::*); | |
template<class T> | |
union union_type { | |
char c; | |
T f; | |
constexpr union_type() : c{} {} | |
}; | |
template<class T> | |
constexpr extern T constexpr_static_init {}; | |
template<auto V> | |
constexpr static std::string_view get_name_if_exists() noexcept { | |
if constexpr (std::is_member_function_pointer_v<decltype(V)>) { | |
return n<V>(); | |
} else { | |
#ifdef _MSC_VER | |
# if _MSVC_LANG >= 202000 | |
return n<&(constexpr_static_init< | |
union_type<decltype(get_base_type(V))> | |
>.f.*V)>(); | |
# else // if_MSVC_LANG < 202000 | |
return ""; | |
# endif // _MSVC_LANG >= 202000 | |
#else // if !defined(_MSC_VER) | |
return n<V>(); | |
#endif // _MSC_VER | |
} | |
} | |
template<auto N> | |
constexpr auto get_name(std::string_view name = get_name_if_exists<N>()) { | |
return name; | |
} |
I see, thank you!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very neat compiler abuse, I was really out of ideas on how to make MSVC spit out member variable names. However this code does not compile for non-trivial types under c++20 on MSVC.
Currently, I've found a fix via an extra level of union nesting(+ constexpr destructors to make this code c++20 compliant)
Here's the minimal change to the invocation of
n
in the member variable branch(signature parsing would have to be adjusted)