我想知道我是否可以将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;
}
};
有什么想法吗?
答案 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*);
所以,在我看来。比较功能是没用的。更改功能的签名以返回某些内容或更好地描述您的业务场景,以便我们更好地了解您的需求。