【问题标题】:Error in using unique_ptr with member function pointer将 unique_ptr 与成员函数指针一起使用时出错
【发布时间】:2013-01-01 00:14:54
【问题描述】:

我有一门课如下

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>)。为什么?谢谢。

【问题讨论】:

  • 错误是什么?此外,不需要整个源代码。
  • VC2010 给出错误 C2296,非法,左运算符包括 std::unique_ptr<_ty>
  • 您可以编辑问题并将其添加到其中吗?

标签: c++ member-function-pointers


【解决方案1】:

似乎operator-&gt;*() 运算符没有为std::unique_ptr&lt;T&gt; 重载。 为什么这个操作符没有被定义的原因并不完全清楚,尽管我认为在提出智能指针的时候还没有处理合适的重载的必要机制。 p>

问题是operator-&gt;*()需要处理返回绑定的结果。对于一个简单的成员函数,这是相当简单的,但对于函数来说,这并不完全是微不足道的。这是unique_ptr&lt;T&gt; 类模板的简约变体,它只是显示了实现的样子:

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-&gt;*() 运算符的一个版本进行一些思考。指向成员变量的指针的版本很简单:它只需要返回对应成员的引用。成员函数的版本需要创建一个可调用对象,其中第一个(隐式)参数绑定到正确的对象。

处理任意数量的参数需要使用可变参数。 unique_ptr&lt;T&gt; 的定义也处理带参数的成员函数指针,可能看起来像这样:

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

【讨论】:

  • 我什至不知道 operator->* 存在!但是为什么 operator-> 不够呢?
  • @user1610015: operator-&gt;() 正在做一些完全不同的事情:它实际上只是通过对operator-&gt;() 的一系列调用,直到最终到达一个普通的指针。指向成员运算符的指针需要提供适当绑定的对象。可以说 -&gt;* 应该是 -&gt; 运算符的应用程序,然后在结果上使用内置的 -&gt;* 运算符,但这不是定义操作的方式(为什么不,我不能立即解释)。
【解决方案2】:

-&gt;* 语法是单个运算符(“指向成员的指针”运算符之一)。该运算符可以重载,但std::unique_ptr 不会这样做。

【讨论】:

    猜你喜欢
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多