我想将不同类型但相同签名的仿函数传递给方法。因此我得出结论,应该使用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 &)>
为什么现在这样做?如果在仿函数中不需要更改代码,我会更好。
答案 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对象。