2011-04-07 57 views
16

我想这一点,和它的一些变化:如何重载 - > *运算符?

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

回答

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是从斯科特迈尔斯在这个题目的优秀PDF(这是唯一的好关于超载的文献operator->*,尽管它是从1999年开始的)。

编辑
这是一个,如果你的编译器支持可变参数模板:http://ideone.com/B6kRF

+0

听起来很可怕。我得看一看。 – Fozi 2011-04-07 20:50:49

+0

@Fozi:相信我,就是这样。尽管我找不到完整的实现,但您的智能指针只需要从某个基地继承而来,并且所有'operator - > *'功能都将存在。 :| – Xeo 2011-04-07 20:53:14

+0

我实际上有一个Delegate类可能可以做到这一点,但它相当重量级,所以我想避免将它作为临时返回。 '(* p)。* method'要简单得多,尽管我希望我可以轻松地支持' - > *'。 – Fozi 2011-04-07 21:00:25

1

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

因此,您可能必须将指针指向成员函数调用的对象,该对象会重载operator()(闭包),如果您没有方便的可变参数模板,这会特别痛苦。

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

如果你不这样做,你将不得不使用宏观假设来模拟可变模板,而这是而不是有趣的事情(即使有些人认为是相反的)。

+0

如果我去C++ 0x路径,不应该p - > *方法已经返回正确的对象?自动返回类型不够? http://ideone.com/lMlyB再次,我卡住了。 – Fozi 2011-04-07 20:49:50

+0

@Fozi:非常好。也许。我不是C + + 0x精明,芽我会说,是的,这将做的伎俩。或者'decltype'也可以。 – 2011-04-07 21:29:39

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类型被定义的方式。

+0

只是不指定返回类型。由于您只有一个'return'语句,所以返回类型会自动推导为内部lambda的类型。否则,解决方案的+1。 :) – Xeo 2012-01-29 23:38:02

+0

@Xeo这只适用于lambdas,但我必须指定运算符' - > *'的返回类型,它是一个'decltype()',但不能在那里指定lambda,因为它使用'this '而且每个lambda实例都有它自己的类型。 :( – Fozi 2012-01-30 00:50:14

+0

哦,对了,我忽略了一些东西:(不过我不认为你会绕过'std :: function',不幸的是。 – Xeo 2012-01-30 01:03:12