我想将函数的赋值封装到std :: function中。我没有传递std :: function或指向std :: function的指针,而是传递从公共抽象类Slot继承的函子(即这些插槽提供了额外的功能)。
我以不同的形状here偶然发现了这个问题。例如。在那里,使用通用槽指针而不是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,它就会编译。
答案 0 :(得分:6)
std::function
复制其论点。由于要分配的对象属于基本类型(并且具有纯虚拟成员函数),因此无法复制。请注意,如果它没有纯虚拟成员函数,则它可能是可复制的,但您会遇到object slicing。
使用std::ref
是安全的,只要您确保std::ref
绑定到的对象的寿命超过所有引用它的对象。
在我看来,最优雅的解决方案是使assignFunctorPtr
成为一个函数模板,它接受真实类型的仿函数(而不是基类型)的参数。如果这是可复制的,则分配将在没有std::ref
的情况下起作用。
template<class SlotType>
void assignFunctorPtr(SlotType* slot_ptr)
{
f = *slot_ptr; // works if SlotType is copyable
}
我相信如果SlotType
只是可移动的话,这个版本也会起作用,但我可能错了。