Consider the following struct:
struct Particle
{
float scale;
float opacity;
float rotation;
};
I want the following to compile:
static_assert(indexOf<&Particle::scale>() == 0);
static_assert(indexOf<&Particle::opacity>() == 1);
static_assert(indexOf<&Particle::rotation>() == 2);
I have managed to implement a working version using Boost.PFR:
template <auto PM>
consteval int indexOf()
{
using ClassType = typename PMTraits<decltype(PM)>::ClassType;
constexpr ClassType obj{};
std::size_t result = -1;
[&]<auto... Is>(std::index_sequence<Is...>)
{
(...,
(
( static_cast<const void*>(&(boost::pfr::get<Is>(obj)))
== static_cast<const void*>(&(obj.*PM)) )
? (result = Is) : 0
)
);
}(std::make_index_sequence<boost::pfr::tuple_size_v<ClassType>>{});
return result;
}
But I am displeased by the fact that I need to create an object of type ClassType in order to make obj.*PM work.
Is there a better way of doing this that (1) does not require the creation of an object at compile-time and/or (2) is more efficient to compile?
You can declare an extern variable to obtain constexpr reference without actually instantitate the object. Also explicitly cache std::array<void const*, N> ptrs<T> so boost::pfr::structure_tie is run only once per struct type.
https://godbolt.org/z/M6KEdbo3n
template <class T>
struct fake_object_wrapper { T const value; };
template <class T>
extern const fake_object_wrapper<T> fake_object;
template<class T>
constexpr auto ptrs = std::apply([](auto const&... ref) {
return std::array{static_cast<void const*>(std::addressof(ref))...};
}, boost::pfr::structure_tie(fake_object<T>.value));
template<auto MemPtr>
constexpr size_t index_of = []<class T, class V>(V T::* p) {
return std::find(ptrs<T>.begin(), ptrs<T>.end(),
std::addressof(fake_object<T>.value.*p)) - ptrs<T>.begin();
}(MemPtr);
////
struct Particle {
float scale;
float opacity;
float rotation;
};
static_assert(index_of<&Particle::scale> == 0);
static_assert(index_of<&Particle::opacity> == 1);
static_assert(index_of<&Particle::rotation> == 2);
Note that this will fail if you have [[no_unique_address]] members in your struct.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With