17

auto_ptr(以及shared_ptr)尽量使它们的使用尽可能透明;也就是说,理想情况下,您应该无法区分您使用的是 auto_ptr 还是指向对象的真实指针。考虑:

class MyClass
{
public:
    void foo() {  }
};

MyClass* p = new MyClass;
auto_ptr<MyClass> ap(new MyClassp);

p->foo();       // No notational difference in using real
ap->foo();      // pointers and auto_ptrs

当您尝试通过指向成员的指针调用成员函数时,会有所不同,因为 auto_ptr 显然没有实现 op->*():

void (MyClass::*memfun)() = &MyClass::foo;

(p->*memfun)();         // OK
(ap->*memfun)();        // Error op->*() missing
(ap.get()->*memfun)();  // OK

为什么 auto_ptr 中不支持 op->*() 以及如何实现它(我已经尝试了一段时间,但最终放弃了)。

4

3 回答 3

8

正如 Luther 指出的那样,它的实施并非易事——但它是可能的。

你必须

  1. 使用模板,因此operator->*可以推断出参数的类型
  2. 使用重载处理可能的限定符和多个函数
  3. 对于成员函数指针,返回一个 callabe 对象,即:
    • 绑定到智能指针指向的实例
    • 实现一个operator()与成员函数等效的签名

暂时忽略限定词,下面是它的基本外观(使用 C++0x 避免手动重复):

// pointer to data member:

template<class T, class D>
D& operator->*(std::auto_ptr<T>& p, D T::*mp) {
    return (*p).*mp;
}

// pointer to member function:

template<class T, class R, class... Args> struct Callable {
    typedef R (T::*MFP)(Args...);
    MFP mfp;
    T& instance;

    Callable(T t, MFP mfp) : instance(t), mfp(mfp) {}

    R operator()(Args... a) {
        return (instance.*mfp)(a...);
    }
};

template<class T, class R, class... Args>
Callable<T, R, Args...>
operator->*(std::auto_ptr<T>& p, R (T::*mfp)(Args...)) {
    return Callable<T, R, Args...>(*p, mfp);
}

但最后,当我们一开始就可以使用绑定成员指针的函子时,为什么还要麻烦呢。

虽然我不能确定,但​​如果你结合以下知识

  • 实现是不平凡的
  • 有一个同样有效的简单替代方案 ( (*p).*m)

...由于所需的工作与此功能带来的收益的比例不佳,它可能通常不会实施。

于 2010-07-17T19:08:18.027 回答
4

实施 ->* 需要解决完美的转发问题:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm

operator->* 必须返回一个与指向成员对象的参数列表相同的可调用对象,正确处理常量、易失性和引用类型。然后它必须使用特殊的魔法来处理默认参数。这是困难的、容易出错的、无法解决的并且占用了太多的编译时间,而且由于指向成员的指针是 C++ 中一个比较流行的特性,所以它们通常被排除在智能指针实现之外。

于 2010-07-17T18:32:17.327 回答
0

我可能错了,但我认为没有办法重载operator->*指向成员函数的指针。这是因为p->*memfun,虽然作为将其视为可调用对象的表达式的一部分是有效的,但它本身并不是有效的表达式,并且没有类型。因此,操作员没有返回的有效类型。

以下内容适用于指向成员的指针,但尝试将其用于指向成员函数的指针会在 GCC 中出现错误,“非静态成员函数的使用无效”,并且会出现内部编译器错误MSVC。

template <class CLASS, typename MEMBER>
MEMBER& operator->*(std::auto_ptr<CLASS>& p, MEMBER CLASS::*m)
{
    return (*p).*m;
}

编辑:正如 Georg 的回答所指出的,您可以使用boost::bind或类似方法为成员函数创建一组重载,最多可达到固定的最大参数数量,但仍然无法为所有可能的成员函数重载运算符。

于 2010-07-17T18:32:27.457 回答