1

我想将不同类型但签名相同的函子传递给方法。因此我得出结论,应该使用 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&)> >

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

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

为什么现在可以使用?如果函子中不需要更改代码,我会更好。

4

2 回答 2

3

你的问题相当于问为什么这不起作用:

struct Integer
{
    int value;
};

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

std::shared_ptr<Integer> p2 = p;

它不起作用,因为它们不是同一类型。仅仅因为您可以将 a 存储MyFunctor在 astd::function<void(const float&)>中并不意味着指向一个的指针可以转换为指向另一个的指针。

你要:

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

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

它可以编译,因为现在您可以转换shared_ptr<MyFunctor>shared_ptr<function<void(const float&)>>,但它不能正常工作。 std::function::operator()()不是虚拟的,所以如果你调用这个函数,它会调用基类' operator(),但是基类不指向任何东西并且会抛出std::bad_cast

于 2013-04-09T17:10:11.560 回答
0

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

于 2013-04-09T17:43:33.103 回答