5

In C++, is it possible to define a sort order for pointers to member functions? It seems that the operator< is undefined. Also, it's illegal to cast to void*.

class A
{
    public:
        void Test1(){}
        void Test2(){}
};

int main()
{
    void (A::* const one)() = &A::Test1;
    void (A::* const two)() = &A::Test2;

    bool equal = one == two; //Equality works fine.
    bool less = one < two; //Less than doesn't.

    return 0;
}

Thanks!

Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
Imbue
  • 3,897
  • 6
  • 40
  • 42
  • What are you trying to achieve? – Martin York Nov 19 '09 at 18:56
  • I'd like to be able to store these pointers in sets or maps. They both require that a sort order be defined. – Imbue Nov 19 '09 at 19:03
  • How dangerous would doing memcmp((void*)&one, (void*) &two, sizeof(one)); be? – Imbue Nov 19 '09 at 19:03
  • 1
    @Imbue: Would probably "work" as a "hack", but only in rather restricted circumstances. In a typical implementation, it will fall apart once multiple inheritance and/or virtual functions are introduced. – AnT stands with Russia Nov 19 '09 at 19:14
  • @Imbue, if you're storing them in maps, you could always use a non-function-ptr key. I assume you're going for some sort of introspection / Qt-like signal-slot mechanism - these use similar techniques. – Fox Nov 19 '09 at 19:18
  • Thanks guys. I'm going to use my memcmp hack for now, and make a note regarding virtual functions. Since == doesn't work for virtual functions, I think this is a good compromise. – Imbue Nov 19 '09 at 19:34

2 Answers2

7

Function pointers are not relationally comparable in C++. Equality comparisons are supported, except for situations when at least one of the pointers actually points to a virtual member function (in which case the result is unspecified).

Of course, you can always introduce an ordering by implementing a comparison predicate and comparing the pointers explicitly (won't look too elegant though, since you can only use equality comparisons). Other possible solutions would cross into the territory of the various implementation-specific "hacks".

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • The work around is as I suggested, which is to implement the member function pointer as a functor. – jmucchiello Nov 19 '09 at 18:31
  • @villapx: Firstly, your emphasised text talks specifically about pointers to **data** members. Secondly, your emphasised text talks specifically about **regular** pointers, not pointers of pointer-to-member type. So no, this is not even close to the OP's situation. – AnT stands with Russia Jan 12 '17 at 16:37
  • Technically, function pointers are relationally comparable in _one_ case in C++03: the case where they both point to the same function. Section 5.9/2 states, "Pointers to objects or functions of the same type (after pointer conversions) can be compared, with a result defined as follows: ... - If two pointers p and q of the same type point to the same object or function, or both point one past the end of the same array, or are both null, then p<=q and p>=q both yield true and pq both yield false. ..." – villapx Jan 12 '17 at 16:45
4

Member function pointers are not actual pointers. You should look at them as opaque structs. What does a method pointer contain:

 struct method_pointer {
     bool method_is_virtual;
     union {
         unsigned vtable_offset; // for a virtual function, need the vtable entry
         void* function_pointer; // otherwise need the pointer to the concrete method
     }
 };

If you could cast this to void* (you can't) all you would have is a pointer the the struct, not a pointer to code. That's why operator<() is undefined as well since the value of the struct's pointer is just where ever it happens to be in memory.

In addition to that, what are you sorting by?

jmucchiello
  • 18,754
  • 7
  • 41
  • 61
  • While it is true that the general physical structure of a member pointer is different from the structure of an ordinary (non-member) pointer, the reason for that has absolutely noting to do with any "self" pointers. In C++ pointers to members are not attached to concrete "selves" in any way. What you describe above looks like a "closure" implementation, but C++ has no closures. – AnT stands with Russia Nov 19 '09 at 19:10
  • I've rewritten my answer. I don't know what I was thinking. – jmucchiello Nov 19 '09 at 20:23
  • jmucchiello, A method pointer does not contain any pointer to an instantiated object of any sort. A method pointer is a pointer to code, not an object/struct or whatever else you want to call it. – Imbue Nov 20 '09 at 20:46
  • good answer, in terms of what is going on behind the scenes, and why you do not want to compare such beasts... – Ichthyo Jan 02 '15 at 09:33