将unique_ptr与成员函数指针一起使用时出错

时间:2013-01-01 00:14:54

标签: c++ member-function-pointers

我有一个课程如下

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&lt; _Ty&gt;)。为什么?感谢。

2 个答案:

答案 0 :(得分: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>
    {
    };
}

答案 1 :(得分:2)

->*语法是单个运算符(“指向成员的指针”运算符之一)。此运算符可能会重载,但std::unique_ptr不会执行此操作。