成员函数可以通过哪些方式进行相互比较?

发布于 2024-11-19 15:11:05 字数 1023 浏览 2 评论 0原文

我想知道是否可以将 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;
    }
};

有什么想法吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

风铃鹿 2024-11-26 15:11:05

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

其他指针比较未指定。

根据§ 8.3.3, 3

“指向成员的指针”类型与“指针”类型不同,

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

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

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.

殊姿 2024-11-26 15:11:05

如果您只想任意将它们排序为集合/映射中的键,那么您可以reinterpret_cast它们。您可能需要像 exact_int::type 这样的模板类,因为 指向成员函数的指针可以有有趣的大小

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.

救赎№ 2024-11-26 15:11:05

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

由于 5.9 不清楚(它处理函数,但没有明确的成员函数),快速浏览一下 5.10(相等比较)可以清楚地将函数与成员函数区分开来:

此外,可以比较指向成员的指针,或者指向
成员和一个空指针常量。指向成员转换的指​​针
执行(4.11)和资格转换(4.4)以将它们
到一个普通类型。如果一个操作数是空指针常量,则
公共类型是另一个操作数的类型。否则,常见的
type 是一个指向成员类型的指针,类似于 (4.4) 之一的类型
操作数,带有 cv 限定签名 (4.4),即
操作数类型的 cv 限定签名的并集。 [笔记:
这意味着任何指向成员的指针都可以与空值进行比较
指针常量。 ] 如果两个操作数都为空,则它们比较相等。
否则,如果只有一个为空,则它们比较不相等。否则如果
要么是指向虚拟成员函数的指针,结果是
未指定。否则它们比较相等当且仅当它们
引用同一最派生对象 (1.8) 的同一成员或
如果用假设的对象取消引用它们,则相同的子对象
关联的类类型。

所以可以使用运算符,==!=的含义是指定的,但是<>的含义;<=>= 未指定。

特别是,没有任何东西强制传递性,因此不清楚将它们放入集合中是否可以。

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.

轻拂→两袖风尘 2024-11-26 15:11:05

虽然描述有点长,但是有一个假人怎么样?
变量并比较其指针,如下所示?

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 的测试。

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.

梨涡少年 2024-11-26 15:11:05

您可以执行类似 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;}

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;}
遇见了你 2024-11-26 15:11:05

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

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

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()
纸短情长 2024-11-26 15:11:05

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

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

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

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文