Closed akrzemi1 closed 9 months ago
You need to pass the field in a template function. Then you use a demangle function inside the current template function.
To demangle, use the special feature from the preprocessor: __PRETTY_FUNCTION__
or __FUNCSIG__
. https://github.com/boostorg/pfr/blob/c695aa0b32ea7665d9e76cfa25655ed6302508e5/include/boost/pfr/detail/core_name20_static.hpp#L88-L96
Then you need to extract the template parameter of the current template function. But the output of the demangle function is not standardized, it's compiler dependent. See BOOST_PFR_CORE_NAME_PARSING
https://github.com/boostorg/pfr/blob/c695aa0b32ea7665d9e76cfa25655ed6302508e5/include/boost/pfr/config.hpp#L115-L126
You may have a look at https://bitwizeshift.github.io/posts/2021/03/09/getting-an-unmangled-type-name-at-compile-time/
And after writing it, I noticed it returns only the type, not the member.... I hope it will help you a little... I also spend an hour without understand how the name of the field is demangled by __PRETTY_FUNCTION__
.
https://github.com/boostorg/pfr/issues/90 It was borned here in the comments :)
Thanks. Bu actually the hard part that I struggle with is how you obtain a member, or a pointer to member. PFR so far only returned tuples of references, and I still do not see how you get from there to the "member", or a pointer to one.
(There are no pointer-to-member in this method (I tried to get here but constexpr time will not work).)
The simplified strategy is the following:
template<class T>
extern const T non_exists;
template<class T>
constexpr auto get_members() {
// this example works only with 3 member
auto& [m1, m2, m3] = non_exists<T>;
return std::tuple{&m1, &m2, &m3};
}
template<class T, std::size_t I, auto* member = std::get<I>(get_members<T>())>
auto get_name()
member
template argument with it's value (code)
{
__PRETTY_FUNCTION__ // this contains:
// member = &non_exists<the_type>.member_name
}
So we "get" the name from the non-existent object's member address.
This is works because the non_exists
object is not used runtime and T
class is not instantiated.
The library uses some workaround, but basically, this is under the hood
We use the structure binding constexpr time on this object to get the members by their pointers (code)
template<class T> constexpr auto get_members() { // this example works only with 3 member auto& [m1, m2, m3] = non_exists<T>; return std::tuple{&m1, &m2, &m3}; }
I still don't get this part. This code only returns pointers (rather than pointers-to-members). boost::pfr::detail::sequence_tuple::get
returns a reference, like int const&
. How can you turn it into a member pointer, or something that you could get a name from?
You right, only references in this code. And it's more than enough to obtain the name. Looks at this: https://godbolt.org/z/31T817Mef No pointer to members in the snippet, only regular pointer(of course, might be changed to reference). That's possible only since C++20, looks at the section "Template non-type arguments" here: https://en.cppreference.com/w/cpp/language/template_parameters
Oh. Thank you. This is brilliant. I think this explanation is worth putting in the docs. This is very interesting on its own, and would contribute to Boost being not only good libraries but also the source to learn interesting programming techniques.
Sure, article in the docs will be created later
There are no pointer-to-member in this method (I tried to get here but constexpr time will not work).
https://godbolt.org/z/Kj9MKosz9 Perhaps line 14 like this is faster at compile time.
constexpr auto first = sv.find_last_of(":.>", last);
than
constexpr auto first = sv.find_last_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789", last);
Would it be possible to describe in "How it works" how obtaining the name is implemented?
I tried to study the library for a couple of hours, and still cannot understand it. Apparently, you must be creating a pointer-to-member somewhere, no? But how is it done?