Search code examples
c++pointersc++17operator-overloadingfunction-pointers

How to implemented comparison/less operator for member method pointers?


From my reading, I understand that it is possible to compare some pointer types in C++ using either operator< or std::less. This is useful if, for example, a pointer is used as a key for a std::map or in a sorted list.

However, I am having difficulty comparing pointer's to member functions.

Here is some example code that does not compile due to operator< not being found (just focus on the comparison of the pointers).

#include <map>

class Base
{
public:
    //...
};

class A : public Base
{
public:
    bool a(int v) { return v < 10; }
};

class B : public Base
{
public:
    bool b(int v) { return v > 10; }
};

using Fn = bool (Base::*)(int);

int main()
{
    A a;
    B b;

    Fn fn1 = static_cast<Fn>(&A::a);
    Fn fn2 = static_cast<Fn>(&B::b);

    std::map<Fn, Base*> functions;
    functions[fn1] = &a;
    functions[fn2] = &b;

    return 0;
};

I was able to get this to compile (albeit with warnings) be implementing operator< using reinterpret_cast to void*. This forces the compiler to do what I want (since all pointers are implemented the same way to my knowledge), but I'm aware that it's a very ugly solution.

Is there a way to compare these pointers?

For those who want to know the real problem context, this is used in a C++ implementation of statecharts as proposed in this book: https://www.state-machine.com/doc/PSiCC.pdf. The map is used to store the "history" for each state. Since states are implemented as member methods, the map creates a "mapping" between a state (the key) and its history (the value).


Solution

  • Object and function pointers are expected to be just numbers. They're typed, and the builtin comparison operators don't impose a strict total order. But since these things are just numbers, a strict total order is expected to exist, and you can access it via std::less and its ilk.

    Member pointers are not just numbers; they are not just an address. As such, there is no strict total order required for them. Nor can you manufacture one. Two member pointers could have the same value representation (ie: separate bits) even if they are "pointing" to different functions, depending on how they get implemented.

    Your reinterpret_cast solution is unreliable.