2013-04-09 104 views
1

我想將不同類型的函子傳遞給一個方法。因此我認爲應該使用std :: function。但是,由於此方法還應存儲對函數對象的引用,所以我想要傳遞shared_ptr(用於生命週期管理)。下面的代碼適用於B類(b.run(...)),但無法編譯爲A類(a.run(...)break)。 當傳遞一個指針而不是函數對象本身時,這個轉換問題的原因是什麼,我該如何繞過它?將函數對象指針傳遞給接受指向std :: function的函數的指針

#include <functional> 
#include <memory> 

class MyFunctor 
{ 
public: 
    void operator()(const float &f) 
    {} 
}; 

template<class FunSig> 
class A 
{ 
public: 
    void run(std::shared_ptr<std::function<FunSig> > f_ptr) 
    { 
     // store f_ptr in a vector 
    } 
}; 

template<class FunSig> 
class B 
{ 
public: 
    void run(std::function<FunSig> f) 
    {} 
}; 

int main() 
{ 
    MyFunctor mf1; 
    std::shared_ptr<MyFunctor> mf2_ptr(new MyFunctor); 

    A<void (const float &)> a; 
    B<void (const float &)> b; 

    a.run(mf2_ptr);  // this breaks! 
    b.run(mf1);   // this works 
} 

編譯器錯誤:

error: no matching function for call to ‘A<void(const float&)>::run(std::shared_ptr<MyFunctor>&)’ 
note: candidate is: 
note: void A<FunSig>::run(std::shared_ptr<std::function<FunSig> >) [with FunSig = void(const float&)] 
note: no known conversion for argument 1 from ‘std::shared_ptr<MyFunctor>’ to ‘std::shared_ptr<std::function<void(const float&)> > 

現在我發現,a.run(...)編譯如果MyFunctor從性病::功能繼承:

class MyFunctor : public std::function<void (const float &)> 

爲什麼這在工作,在忙?如果在函子中沒有必要更改代碼,我會更好。

+1

這裏的問題是一個類型轉換。 MyFunctor *是指向MyFunctor結構的指針,std :: function *是指向std :: function對象的指針:當MyFunctor從std :: function繼承時,代碼會編譯,因爲它現在是一個子類std :: function,因此可以隱式轉換。 – IdeaHat 2013-04-09 16:23:02

回答

3

你的問題就相當於問爲什麼這不起作用:

struct Integer 
{ 
    int value; 
}; 

std::shared_ptr<int> p(new int(1)); 

std::shared_ptr<Integer> p2 = p; 

它不工作,因爲它們不是同一類型。僅僅因爲您可以將MyFunctor存儲在std::function<void(const float&)>中並不意味着指向一個指針的指針可以轉換爲指向另一個的指針。

你想:

auto mf2_ptr = std::make_shared<std::function<void (const float &)>>(MyFunctor()); 
a.run(mf2_ptr); 

Now I discovered that a.run(...) compiles if MyFunctor inherits from std::function:

它編譯,因爲現在你可以轉換到shared_ptr<MyFunctor>shared_ptr<function<void(const float&)>>,但它無法正常工作。 std::function::operator()()不是虛擬的,所以如果你調用這個函數,它會調用基類'operator(),但是基類不指向任何東西,並且會拋出std::bad_cast

+0

非常感謝。實際上,在睡眠良好之後,這是非常明顯的......所以要麼傳遞一個指向std:function的指針,要麼所有的函數都從一個普通的類繼承。 – spinxz 2013-04-10 07:54:14

0

我不是很明白你爲什麼要引用std :: function對象。除非你真的想共享引用語義(例如,別人可以修改正在使用的函數對象的能力),否則直接存儲一個std :: function對象。

+0

請參閱[這個問題](http://stackoverflow.com/questions/14882867/boostsignals2-descruction-of-an-object-with-the-slot)。我想要類似的東西來跟蹤仿函數的生命週期。 – spinxz 2013-04-10 09:26:54