如何重载 - > *运算符?

时间:2011-04-07 20:23:36

标签: c++

我尝试了这个,以及它的一些变化:

template<class T>
class Ptr {
public:
    Ptr(T* ptr) : p(ptr) {}
    ~Ptr() { if(p) delete p; }

    template<class Method>
    Method operator ->* (Method method)
    {
        return p->*method;
    }

private:
    T *p;
};

class Foo {
public:
    void foo(int) {}
    int bar() { return 3; }
};

int main() {
    Ptr<Foo> p(new Foo());

    void (Foo::*method)(int) = &Foo::foo;
    int (Foo::*method2)() = &Foo::bar;

    (p->*method)(5);
    (p->*method2)();

    return 0;
}

doesn't work。问题是我真的不知道期待什么作为参数或返回什么。关于这一点的标准对我来说是不可理解的,因为Google没有提出任何有用的信息,我想我并不孤单。

编辑:另一次尝试,使用C ++ 0x:http://ideone.com/lMlyB

3 个答案:

答案 0 :(得分:8)

operator->*的返回表示被调用过程中的一个函数,唯一缺失的部分是参数。因此,您必须返回一个仿函数,该仿函数使用给定的参数调用给定对象上的给定函数:

// PTMF = pointer to member function
template<class Obj>
struct PTMF_Object{
  typedef int (Obj::*ptmf)(double,std::string); // example signature

  PTMF_Object(Obj* obj, ptmf func)
    : obj_(obj)
    , func_(func)
  {}

  int operator()(double d, std::string str){
    return (obj_->*func_)(d,str);
  }

  Obj* obj_;
  ptmf func_;
};

template<class T>
struct SmartPtr{
  // ...

  PTMF_Object<T> operator->*(PTMF_Object<T>::ptmf func){
    return PTMF_Object<T>(p, func);
  }
  // ...
};

int main(){
  SmartPtr<Foo> pf(new Foo());
  typedef int (Foo::*Foo_ptmf)(double,std::string);
  Foo_ptmf method = &Foo::bar;

  (pf->*method)(5.4, "oh hi");
}

<强> EDIT2
Here是Scott Meyers关于这个主题的优秀pdf(这是关于重载operator->*的唯一优秀文献,尽管它来自1999年)。

修改
如果您的编译器支持可变参数模板,那么这是一个:http://ideone.com/B6kRF

答案 1 :(得分:2)

我回到了这个问题,我找到了一个简单的解决方案:

template<class Ret, class... Args>
auto operator ->* (Ret (T::*method)(Args...)) -> std::function<Ret(Args...)>
{
  return [this, method](Args&&... args) -> Ret {
    return (this->p->*method)(std::forward<Args>(args)...);
  };
}

可以找到完整测试用例的实现here

我在这个解决方案中唯一不喜欢的是使用std::function。如果有人知道直接退回lambda的方法,请告诉我。我有预感,因为lambda类型的定义方式可能无法实现。

答案 2 :(得分:1)

IIRC,operator->*的返回类型应该是一个可以作为函数调用的对象。

所以你可能必须将指向成员函数调用的指针转发给一个重载operator()(一个闭包)的对象,如果你没有方便的可变参数模板,那就特别痛苦了。

如果你有C ++ 0X,你有闭包和可变参数模板,你的问题可以用几行通用代码来解决。

如果你不这样做,你将不得不使用宏技巧来模拟可变参数模板,这是有趣(即使有些人认为相反)。