2013-01-01 48 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不这样做。