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;

タイプが違うから仕方ない。MyFunctoraに aを格納できるからとstd::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 に答える