Data member pointers as associative container keys

168 views Asked by At

I am trying to create an std::set of pointers to data members. However, I can't find a method to sort or hash such pointers.

They can't be compared with operator<, they don't seem to be supported by std::less and there is no standard integer type that is guaranteed to hold their representation (they might not fit in std::uintptr_t).

This is what I tried first (https://godbolt.org/z/K8ajn3rM8) :

#include <set>

struct foo
{
    int x;
    int y;
};

using t_member_ptr = int (foo::*);

const std::set<t_member_ptr> members = {
    &foo::x,
    &foo::y
};

It produces the error error: invalid operands of types 'int foo::* const' and 'int foo::* const' to binary 'operator<'. The full error message also implies this occurs during instantiation of std::less.

I found a similar question (Set of pointer to member) but it dates back to C++14 and the answers boil down to "put your pointers in a vector and perform a linear search instead".

Has there been any changes with C++17 or C++20 that make it possible to use pointers to data members as keys for standard associative containers?

1

There are 1 answers

5
HolyBlackCat On BEST ANSWER

Compare them bytewise, e.g. using this comparator:

#include <cstring>
#include <type_traits>

struct BitLess
{
    template <typename T>
    requires std::has_unique_object_representations_v<T>
    constexpr bool operator()(const T &a, const T &b) const
    {
        return std::memcmp(reinterpret_cast<const char *>(&a), reinterpret_cast<const char *>(&b), sizeof(T)) < 0;
    }
};

Checking std::has_unique_object_representations_v<T> ensures that there's no padding inside. It tried it on GCC, Clang, and MSVC, and it returned true for member pointers on all three.