4

我想将仿函数对 std::function 的分配封装到一个方法中。我必须传递从通用抽象类 Slot 继承的仿函数,而不是传递 std::function 或指向 std::function 的指针(即,这些槽提供附加功能)。

我在这里以不同的形式偶然发现了这个问题。例如,使用通用槽指针而不是 std:functions 的动机是函子的生命周期管理。

下面的代码说明了这个问题。请参阅 assignFunctorPtr(...) 方法。

#include <iostream>
#include <functional>

template<class FunSig>
class Slot;

template<class R>
class Slot<R()>
{
public:
    typedef R Ret_type;

public:
    virtual ~Slot() {}
    virtual Ret_type operator()() = 0;
};

template<class R, class A1>
class Slot<R(A1)>
{
public:
    typedef R Ret_type;
    typedef A1 Arg1_type;

public:
    virtual ~Slot() {}
    virtual Ret_type operator()(Arg1_type) = 0;
};

class TestSlot: public Slot<void (float &)>
{
public:
    void operator()(float& f)
    { std::cout << f ;}
};


template<class FunSig>
class TestSignal
{
public:
    typedef Slot<FunSig> Slot_type;

    std::function<FunSig> f;

    void assignFunctorPtr(Slot_type* slot_ptr)
    {
        //f = std::ref(*slot_ptr);   // A -> works!
        f = *slot_ptr;               // B -> compiler error!
    }
};


int main()
{
    TestSlot* slot = new TestSlot;
    TestSignal<void (float &)>* signal = new TestSignal<void (float &)>;

    signal->assignFunctorPtr(slot);
}

如果在 assignFunctorPtr(...) 中使用版本 B,则此代码会中断。

Error: "error: cannot allocate an object of abstract type ‘Slot<void(float&)>’
note:   because the following virtual functions are pure within ‘Slot<void(float&)>’"

如果使用 assignFunctorPtr(...) 中的版本 A,它会编译。

  • 如果 std::ref 用于包装仿函数,为什么它会编译?
  • 因此 std::function 对仿函数的具体要求是什么(另见std::function 参考
  • 解决此问题的正确/最佳方法是什么?
  • 使用 std::ref 可以节省吗?
4

1 回答 1

6

std::function复制它的论点。由于您要分配的对象是基类型(并且具有纯虚成员函数),因此无法复制它。请注意,如果它没有纯虚成员函数,它可能是可复制的,但您会遭受对象切片的影响。

std::ref只要您确保std::ref绑定到的对象的寿命比对其的所有引用都长,使用是安全的。

在我看来,最优雅的解决方案是制作assignFunctorPtr一个函数模板,它接受真正类型的函子(而不是基本类型)的参数。如果这是可复制的,则分配将在没有std::ref.

template<class SlotType>
void assignFunctorPtr(SlotType* slot_ptr)
{
    f = *slot_ptr;               // works if SlotType is copyable
}

我相信如果只是可移动的,这个版本也可以工作SlotType,但我可能错了。

于 2013-04-30T12:23:47.167 回答