In what ways member functions may be compared to each other?

末鹿安然 提交于 2019-12-06 13:49:23

问题


I would like to know if I can compare 2 member functions with the "<" operator. I can do "==" but I can't use it in the case below. I tried casting them to void* but that won't work either.

template <class Receiver, class Sender>
class CallBack2 : public ICallBack2 {

protected:

    Receiver* receiver;
    void(Receiver::*function)(Sender*);
    Sender* sender;

public:

    CallBack2(Receiver* _receiver, void(Receiver::*_function)(Sender*), Sender* _sender) : receiver(_receiver), function(_function), sender(_sender) {};
    virtual ~CallBack2() {};

    virtual void callBack() {
        (receiver->*function)(sender);
    }

    virtual bool operator<(const ICallBack2* _other) const {
        CallBack2<Receiver, Sender>* other = (CallBack2<Receiver, Sender>*)_other;
        if (receiver < other->receiver) {
            return true;
        } else if (receiver == other->receiver && function < other->function) {
            return true; // this line gives the error
        }
        return false;
    }
};

Any ideas please?


回答1:


If you just want to arbitrarily order them to be keys in a set/map, then you can reinterpret_cast them. You may need a template class like exact_int<sizeof(void (Foo::*bar)())>::type because pointers to member functions can have funny sizes.




回答2:


C++03 § 5.9, which covers the semantics of the built-in <, >, <= and >=, doesn't mention pointers to members and states:

Other pointer comparisons are unspecified.

According to § 8.3.3, 3

The type "pointer to member" is distinct from the type "pointer",

As a result, we can conclude the result of relational operators applied to pointers to members (whether functions or fields) is unspecified.

Note that "unspecified behavior" is different from "undefined behavior", but still means you can't usefully apply the operators as different implementations may have different results. "Unspecified" basically means the implementation gets to define the behavior.




回答3:


5.9.7 (relational operators): "Other pointer comparisons are unspecified".

Since 5.9 is unclear (it deals with functions, but not explicitly member functions), a quick look at 5.10 (equality comparison) clearly separates functions from member functions:

In addition, pointers to members can be compared, or a pointer to member and a null pointer constant. Pointer to member conversions (4.11) and qualification conversions (4.4) are performed to bring them to a common type. If one operand is a null pointer constant, the common type is the type of the other operand. Otherwise, the common type is a pointer to member type similar (4.4) to the type of one of the operands, with a cv-qualification signature (4.4) that is the union of the cv-qualification signatures of the operand types. [Note: this implies that any pointer to member can be compared to a null pointer constant. ] If both operands are null, they compare equal. Otherwise if only one is null, they compare unequal. Otherwise if either is a pointer to a virtual member function, the result is unspecified. Otherwise they compare equal if and only if they would refer to the same member of the same most derived object (1.8) or the same subobject if they were dereferenced with a hypothetical object of the associated class type.

So you can use the operators, the meaning of == and != is specified, but the meaning of <, >, <= and >= is unspecified.

In particular, nothing enforces transitivity, so it is not clear whether putting them in a set is ok or not.




回答4:


Though the description gets a little lengthy, how about having a dummy variable and comparing its pointer like the following?

template< class T >
struct comparable_value {
    T value;
    char *id;

    comparable_value( T value, char* id ) : value( value ), id( id ) {}

    bool operator<( comparable_value const& x ) const {
        return std::less< char* >()( id, x.id );
    }
};

template< class T, T V >
comparable_value< T > get_comparable_value() {
    static char dummy;
    return comparable_value< T >( V, &dummy );
}

struct A {
    void f() { puts( "f" ); }
    void g() { puts( "g" ); }
};

int main() {
    typedef void (A::*MF)();
    typedef std::set< comparable_value< MF > > set_t;
    set_t s;
    s.insert( get_comparable_value< MF, &A::f >() );
    s.insert( get_comparable_value< MF, &A::g >() );
    A a;
    for ( set_t::iterator i = s.begin(), e = s.end();  i != e;  ++ i )
        (a.*i->value)();
}

Here is a test on ideone.




回答5:


You could do something like Ise's idea, only keep it contained to Callback2 class so that you don't need to change anything that uses the class.

template <class Receiver, class Sender>class CallBack2 : public ICallBack2 {
private:
   static int nextSequenceNumber;
   int sequenceNumber;

//snip

public:
  CallBack2(Receiver* _receiver, void(Receiver::*_function)(Sender*), Sender* _sender) :
   sequenceNumber(nextSequenceNumber++), receiver(_receiver), function(_function), sender(_sender) {};

//snip

virtual bool operator<(const ICallBack2* _other) const {
  return sequenceNumber<_other->sequenceNumber;}



回答6:


Taking the address of a member function results in a constant expression that cannot be stored in a variable. It can only be used to compare for equality to another expression that represenst the address of a function taking the same set of parameters, with the same return type and the same type of this pointer.

    class a 
    {
    public:
        virtual void test();
    };
    class b
    {
    public:
        virtual void test();
    };

    ....
    a *pa = new a;
    b *pb = new b;

    if (pb->test == pa->test) // legal, but  false
    if (pb->test==pb::test) // legal and true
    // pa->test will evaluate to a::test, although calling pa->test() would call
    // b::test()



回答7:


It makes no sense to compare two function pointers. What you could compare is actually the return value of those functions:

*function(sender) < *(other->function)(sender)

but in your case you declare the function as:

void(Receiver::*function)(Sender*);

so, in my opinion. Comparing the functions is useless. Either change the function's signature to return something or better describe your business scenario so we can better understand what you want.



来源:https://stackoverflow.com/questions/6662917/in-what-ways-member-functions-may-be-compared-to-each-other

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!