使用unique_ptr与成员函数指针时出错 [英] Error in using unique_ptr with member function pointer

查看:279
本文介绍了使用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)(); //错误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>)。为什么?感谢。

解决方案

似乎 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 indexes< sizeof ...(A)-1> :: type())){
return this-> bind_members(mem,
typename indices< sizeof ...(A)-1> :: type());
}
};

主要技巧在于为参数创建一系列合适的占位符。相应的辅助类是这样定义的:

  template< int ... Indices>结构索引; 
模板<>结构索引-1 {typedef indices<>类型; };
template< int ... Indices>
struct indices< 0,Indices ...>
{
typedef indices< 0,Indices ...>类型;
};
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>
{
};
}


I have a class as below

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

private:
    int m_key;
};

I test using unique_ptr with member function pointer

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

The first one gives a compilation error (VC2010 gives error C2296, illegal, left operator includes std::unique_ptr<_Ty>). Why? Thanks.

解决方案

It seems the operator->*() operator isn't overloaded for std::unique_ptr<T>. The reason why this operator isn't defined isn't entirely clear although I think that at the time when the smart pointers were proposed the necessary mechanics for dealing with the suitable overloads were not in place.

The problem is that operator->*() needs to deal with returning the bound result. For a simple member function this is reasonably simple but for functions it isn't entirely trivial. Here is a minimalistic variation of the unique_ptr<T> class template which just shows the implementation would look like:

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_);
    }
};

This version merely copes with pointers to member variables and pointer to member functions with no arguments. I need to meditate a bit over a version of the operator->*() operator for arbitrary number of arguments. The version for pointer to member variables is trivial: It just needs to return a reference the corresponding member. The version for member functions needs to create a callable object with the first (implicit) parameter being bound to the correct object.

Dealing with an arbitrary number of arguments take a bit of playing with variadic arguments. A definition of unique_ptr<T> also dealing with member functions pointers taking arguments could look something like this:

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());
    }
};

The main trick consists in creating a sequence of suitable placeholders for the arguments. The corresponding helper classes are defined thus:

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>
    {
    };
}

这篇关于使用unique_ptr与成员函数指针时出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆