将函数对象指针传递给接受指向std :: function的指针的函数

时间:2013-04-09 15:57:33

标签: c++ templates c++11 std-function

我想将不同类型但相同签名的仿函数传递给方法。因此我得出结论,应该使用std :: function。但是,由于此方法还应存储对函数对象的引用,而不是传递shared_ptr(用于生命周期管理)。下面的代码适用于B类(b.run(...)),但无法为A类编译(a.run(...)中断)。 当传递指针而不是函数对象本身时,这个转换问题的原因是什么?如何绕过它呢?

#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继承自std :: function:

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

为什么现在这样做?如果在仿函数中不需要更改代码,我会更好。

2 个答案:

答案 0 :(得分: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);
  

现在我发现a.run(...)编译,如果MyFunctor继承自std :: function:

它会进行编译,因为现在您可以将shared_ptr<MyFunctor>转换为shared_ptr<function<void(const float&)>>,但它无法正常工作。 std::function::operator()()不是虚拟的,所以如果调用该函数,它将调用基类“operator(),但基类不指向任何内容,并将抛出std::bad_cast

答案 1 :(得分:0)

我不太明白你为什么要引用std :: function对象。除非你真的想要共享引用语义(例如,其他人修改正在使用的函数对象的能力),否则只需直接存储一个std :: function对象。