2013-01-01 47 views
4

我有一個類如下面錯誤使用的unique_ptr與成員函數指針

class A 
{ 
public: 
    A(int key)   : m_key(key) {} 
    int Key() const  {return m_key;} 

private: 
    int m_key; 
}; 

我測試使用的unique_ptr與成員函數指針

int (A::*MemFun)() const; 
MemFun = &A::Key; 
(std::unique_ptr<A>(new A(10))  ->*MemFun)(); // Error C2296 
(std::unique_ptr<A>(new A(10)).get() ->*MemFun)(); // okay 
(*std::unique_ptr<A>(new A(10))  .*MemFun)(); // okay 

第一個給出了一個編譯錯誤(VC2010給出錯誤C2296,非法,左操作符包括std :: unique_ptr < _Ty>)。爲什麼?謝謝。

+0

什麼是錯誤?另外,不需要整個來源。 – sashoalm

+0

VC2010給出錯誤C2296,非法,左操作符包括std :: unique_ptr <_Ty> – user1899020

+0

你可以編輯問題並將其添加到它嗎? – sashoalm

回答

5

看起來operator->*()運算符沒有超載爲std::unique_ptr<T>。原因爲什麼這個算子沒有被定義是不完全清楚的,儘管我認爲在智能指針被提出的時候,處理合適超載的必要機制並沒有到位。

問題是operator->*()需要處理返回綁定結果。對於一個簡單的成員函數來說,這是相當簡單的,但對於函數來說,它並非完全無關緊要。這裏是unique_ptr<T>類模板的簡約變化,這只是顯示的實施將看起來像:

template <typename T> 
struct unique_ptr 
{ 
    T* p_; 
    unique_ptr(T* p): p_(p) {} 
    T* operator->() { return this->p_; } 
    template <typename R> 
    R& operator->*(R T::*mem) { return this->p_->*mem; } 
    template <typename R> 
    auto operator->*(R (T::*mem)()) ->decltype(std::bind(mem, this->p_)) 
    { 
     return std::bind(mem, this->p_); 
    } 
}; 

該版本僅與指針的成員變量和指針成員函數不帶參數的對應。我需要對operator->*()運算符的版本進行一些修改,以獲得任意數量的參數。成員變量指針的版本很簡單:它只需要返回一個引用對應的成員。成員函數的版本需要創建一個第一個(隱式)參數綁定到正確對象的可調用對象。

處理任意數量的參數需要使用可變參數進行一些處理。的unique_ptr<T>的定義還面臨着採取論證會是這個樣子的成員函數指針:

template <typename T> 
struct unique_ptr 
{ 
private: 
    T* p_; 
    template <typename R, typename... A, int... I> 
    auto bind_members(R (T::*mem)(A...), indices<I...>) 
     -> decltype(std::bind(mem, this->p_, placeholder<I + 1>()...)) 
    { 
     return std::bind(mem, this->p_, placeholder<I + 1>()...); 
    } 

public: 
    unique_ptr(T* p): p_(p) {} 
    T* operator->() const { return this->p_; } 
    template <typename R> 
    R& operator->*(R T::*mem) { return this->p_->*mem; } 
    template <typename R> 
    auto operator->*(R (T::*mem)()) ->decltype(std::bind(mem, this->p_)) 
    { 
     return std::bind(mem, this->p_); 
    } 
    template <typename R, typename... A> 
    auto operator->*(R (T::*mem)(A...)) 
     -> decltype(this->bind_members(mem, 
       typename indices<sizeof...(A) - 1>::type())) { 
     return this->bind_members(mem, 
      typename indices<sizeof...(A) - 1>::type()); 
    } 
}; 

主要的竅門在於創建參數適合的佔位符的序列。相應的幫助類是這樣定義的:

template <int... Indices> struct indices; 
template <> struct indices<-1> { typedef indices<> type; }; 
template <int... Indices> 
struct indices<0, Indices...> 
{ 
    typedef indices<0, Indices...> type; 
}; 
template <int Index, int... Indices> 
struct indices<Index, Indices...> 
{ 
    typedef typename indices<Index - 1, Index, Indices...>::type type; 
}; 

template <int I> 
struct placeholder 
    : std::integral_constant<int, I> 
{ 
}; 

namespace std 
{ 
    template <int I> 
    struct is_placeholder<placeholder<I>> 
     : std::integral_constant<bool, true> 
    { 
    }; 
} 
+0

我甚至不知道運算符 - > *存在!但爲什麼不算operator->足夠? – user1610015

+0

@ user1610015:'operator - >()'做了一些完全不同的事情:它真的只是傳遞一系列對'operator - >()'的調用,直到最終達到一個普通指針。成員操作符的指針需要提供一個合適的綁定對象。可能會認爲' - > *'應該是' - >'運算符的應用程序,然後對結果使用內置的' - > *'運算符,但這不是操作的定義方式(爲什麼不呢,我不能馬上解釋)。 –

2

->*語法是單個運算符(「指向成員的指針」運算符之一)。該操作員可能超載,但std::unique_ptr不這樣做。