2013-04-30 45 views
4

我想將函子的賦值封裝到std :: function中。我不得不傳遞std :: function或指向std :: function的指針,而必須傳遞從通用抽象類Slot繼承的函子(即這些插槽提供附加功能)。將抽象函數賦值給std :: function - 爲什麼是std :: ref解決方案?

我偶然發現了不同形狀的這個問題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版本。

  • 如果使用std :: ref來包裝函子,它爲什麼會編譯?
  • 因此,函子的std :: function的具體要求是什麼(請參閱std::function reference
  • 什麼是解決此問題的正確/最佳方法?
  • 保存使用std :: ref嗎?

回答

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只是移動,但我可能是錯在那裏。

+2

模板版本可以通過'SlotType && slot'和'f = std :: forward (slot);'在我的身上得到改進。通過這種方式,調用者可以根據他傳入的內容來選擇是移動還是複製,也不需要更多指針。 – David 2013-04-30 12:34:38

+0

感謝您的回答。我檢查了你的建議,使assignFunctorPtr(...)成員模板,它編譯好! – spinxz 2013-04-30 12:35:31

相關問題