成员函数可以以何种方式相互比较?

时间:2011-07-12 10:41:31

标签: c++ function operator-overloading compare

我想知道我是否可以将2个成员函数与“<”进行比较运营商。我可以做“==”但我不能在下面的情况下使用它。我尝试将它们转换为 void * ,但这也无效。

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;
    }
};

有什么想法吗?

7 个答案:

答案 0 :(得分:3)

C ++ 03 § 5.9,它涵盖了内置&lt;,&gt;,&lt; =和&gt; =的语义,没有提到指向成员和状态的指针:

  

其他指针比较未指定。

根据§ 8.3.3,3

  

“指向成员的指针”类型与“指针”类型

不同

因此,我们可以得出结论应用于成员指针(无论是函数还是字段)的关系运算符的结果是未指定的。

请注意,“未指定的行为”与“未定义的行为”不同,但仍然意味着您无法有效地应用运算符,因为不同的实现可能会有不同的结果。 “未指定”基本上意味着实现可以定义行为。

答案 1 :(得分:1)

如果您只是想任意地将它们命名为集合/地图中的键,那么您可以reinterpret_cast它们。您可能需要exact_int<sizeof(void (Foo::*bar)())>::type之类的模板类,因为pointers to member functions can have funny sizes

答案 2 :(得分:1)

5.9.7(关系运算符):“其他指针比较未指定”。

由于5.9不清楚(它处理函数,但没有明确的成员函数),快速查看5.10(相等比较)清楚地将函数成员函数分开:

  

此外,可以比较指向成员的指针,也可以指向指针   成员和空指针常量。指向成员转换的指​​针   (4.11)和资格转换(4.4)是为了带来它们   一般的类型。如果一个操作数是空指针常量,则   common类型是另一个操作数的类型。否则,共同的   type是一个指向成员类型的指针,类似于(4.4)的类型之一   操作数,具有cv资格签名(4.4)即   操作数类型的cv限定签名的并集。 [注意:   这意味着任何指向成员的指针都可以与null进行比较   指针常数。如果两个操作数均为空,则它们相等。   否则,如果只有一个为null,则它们比较不相等。否则如果   要么是指向虚拟成员函数的指针,结果是   不确定的。否则他们比较等于,如果他们愿意的话   引用相同的最派生对象(1.8)或相同的成员   如果他们被一个假设的对象取消引用,则使用相同的子对象   相关的类类型。

因此,您可以使用运算符,指定==!=的含义,但<><=和{的含义{1}}未指定。

特别是,没有什么可以强制实现传递性,因此不清楚将它们放入集合中是否合适。

答案 3 :(得分:1)

虽然描述有点冗长,但是假人怎么样 变量并比较它的指针如下?

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)();
}

以下是ideone的测试。

答案 4 :(得分:0)

你可以做一些像Ise的想法,只保留它包含在Callback2类中,这样你就不需要改变任何使用该类的东西了。

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;}

答案 5 :(得分:-1)

获取成员函数的地址会产生一个不能存储在变量中的常量表达式。它只能用于比较与另一个表达式相等的表达式,该表达式表示采用相同参数集的函数的地址,具有相同的返回类型和相同类型的指针。

    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()

答案 6 :(得分:-1)

比较两个函数指针是没有意义的。您可以比较的实际上是这些函数的返回值:

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

但在您的情况下,您将该函数声明为:

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

所以,在我看来。比较功能是没用的。更改功能的签名以返回某些内容或更好地描述您的业务场景,以便我们更好地了解您的需求。