タイプは異なるが同一のシグネチャのファンクターをメソッドに渡したいと思います。したがって、 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 &)>
なぜ今これが機能するのですか?ファンクターでコードの変更が必要ない場合は、もっといいでしょう。