2

底部的原始问题。

我想我明白你们现在在说什么——因为成员函数指针的内部结构是编译器/机器特定的,所以我真的不可能做到这一点。因此,即使在我测试它时它可以工作——我不能保证它会在其他编译器/机器上运行。

那么还有其他方法可以实现我想要的吗?

我有一个模板类和该类的基本模板类,并且我有一个委托类,其中包含委托类在调用时应调用的所有事件的 std::map。

我需要一个映射的原因是,既要确保相同的成员函数(指向成员函数的事件)不会被添加一次,又可以使用最初使用的对象和成员函数从映射中删除事件实例化事件对象。

template <class T_arg1> struct EventBase1
{
public:
    bool operator < (const EventBase1 &event1) const { return _key < event1._key; };
    virtual void operator()(T_arg1 t1) const {};
    std::pair<intptr_t, intptr_t> _key;
};

template <class T, class T_arg1> struct Event1: public EventBase1<T_arg1>
{
    template <class T_arg1> friend class Delegate1;
    typedef typename void (T::*Method)(T_arg1);
private:
    Method _method;
    T* _object;
public:
    Event1(T* object, Method method): _object(object), _method(method)
    {
        _key = std::pair<intptr_t, intptr_t>(reinterpret_cast<intptr_t>(object), reinterpret_cast<intptr_t>( reinterpret_cast<void*&>(method)));
    };
    virtual void operator()(T_arg1 t1) const {
        (_object->*_method)(t1);
    };
};

template <class T_arg1> class Delegate1
{
public:
    typedef typename EventBase1<T_arg1> T_event;
    void operator += (T_event* observer)
    {
        assert(observer);
        _observers[*observer] = observer;
    };
    void operator -= (const T_event &observer)
    {
        std::map<T_event, T_event*>::iterator i = _observers.find(observer);
        if(i != _observers.end()) {
            delete i->second;
            _observers.erase(i);
        }
    };
    void operator()(T_arg1 t1)
    {
        for(std::map<T_event, T_event*>::iterator i = _observers.begin(); i != _observers.end(); i++) {
            (*(i->second))(t1);
        }
    };
private:
    std::map<T_event, T_event*> _observers;     
};

原始问题:

我将函数指针存储在 a 中std::map,并且我正在为地图生成我的密钥,如下所示std::pair<int, int>( (int)((int*)object), (int)(static_cast<const void*>(&method)) )

method是函数(方法)指针,object是指向方法对象的指针。

它有效,但是我偷偷怀疑我获得密钥第二部分的方式并不完全正确。

我从来没有完全理解函数指针,但我想我得到的是指针的地址而不是函数的地址,编译器不会让我这样做((int)(static_cast<const void*>(method)))

所以我的问题是 - 我如何从函数指针中获取一个唯一键,如果我稍后从另一个指向相同方法的函数指针中获取键,这将是相同的?

在此先感谢,马丁

4

2 回答 2

4

第二个是不合法的:形式上,您不能将指向函数的指针转换为指向数据的指针(并且 avoid*是指向数据的指针)。此外,不能保证您能够将任何指针转换为 int; int仅当至少与指针一样大时,转换才合法(这意味着您的代码应该无法在大多数 64 位系统上编译)。

有几种方法可以解决这个问题。首先,在大多数(全部?)现代机器上,函数指针和数据指针确实具有相同的大小和表示。(事实上​​,Posix 需要它。即使在我使用的第一台 Unix 机器上不是这种情况。)如果我们假设这一点,您可以通过使用来保证足够大的整数类型intptr_t,并使用附加的“欺骗”编译器间接级别:

std::pair<intptr_t, intptr_t>(
    reinterpret_cast<intptr_t>( reinterpret_cast<void*&>( object ) ),
    reinterpret_cast<intptr_t>( reinterpret_cast<void*&>( method ) ) )

(这假设objectandmethod是您指向对象和函数的指针。)

请注意,这不适用于指向成员函数的指针。指向成员函数的指针是完全不同的野兽,我认为没有任何有效的方法可以以这种方式将它们用作键(因为在某些情况下,它们可能并且经常包含填充或未设置的字段) .

就此而言,正式地,即使对于普通指针,也不能真正保证这一点。该标准允许指针具有无关位,或者允许几个不同的指针表示比较相等。然而,在实践中,它在大多数(所有?)现代机器上都是安全的。

于 2012-08-16T08:30:54.160 回答
2

你应该写得很好:

reinterpret_cast<uintptr_t>(method)

[编辑] - 对于指向方法的指针,您必须使用 c 风格的强制转换,如本 SO 中所述:reinterpret_cast to void* not working with function pointers

&method 是因为您怀疑指向指针的指针,所以它不是您想要的

uintptr_t 比 int 更好,因为它保证与指针大小相同

于 2012-08-16T08:21:43.047 回答