2011-04-07 58 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