web-dev-qa-db-ja.com

テンプレートのメンバー関数ポインターによるshared_ptrのメンバー関数呼び出し

これは、ポインター(またはオブジェクトのようなポインター)とメンバー関数を取るテンプレート関数です。

template <typename Ptr, typename MemberFunctor>
int example(Ptr ptr, MemberFunctor func )
{
    return (ptr->*func)();
}

通常のポインターで使用すると機能する場合:

struct C
{
    int getId() const { return 1; }
};

C* c = new C;
example(c, &C::getId);    // Works fine

ただし、スマートポインタでは機能しません。

std::shared_ptr<C> c2(new C);
example(c2, &C::getId);

エラーメッセージ:

error: C2296: '->*' : illegal, left operand has type 'std::shared_ptr<C>'

どうして?と両方で動作するものを作るには?

24
Meena Alfons

std::shared_ptr はサポートしていません pointer-to-memberアクセス​​演算子 (つまり、->*および.*)。そのため、->*を直接指定してメンバー関数ポインターを呼び出すことはできません。呼び出し構文を変更して、operator*およびoperator.*を使用することができます。これは、生のポインターとスマートポインターの両方で機能します。

template <typename Ptr, typename MemberFunctor>
int example(Ptr ptr, MemberFunctor func )
{
    return ((*ptr).*func)();
}

[〜#〜]ライブ[〜#〜]

23
songyuanyao

std::shared_ptrにはoperator->*がありません。主なオプションは2つあります。

std::shared_ptr(おそらくstd::unique_ptrの場合も1つ)を受け取るオーバーロードを作成できます。

template <typename T, typename MemberFunctor>
int example(std::shared_ptr<T> ptr, MemberFunctor func )
{
    return ((ptr.get())->*func)();
}

ただし、exampleTへの参照を取得させ、その上でfuncを呼び出すことをお勧めします。 exampleは、ポインターがどのように格納されるかについて何も知る必要がないため、これらの追加のオーバーロードのすべてを必要とするべきではありません。

template <typename T, typename MemberFunctor>
int example(T&& t, MemberFunctor func )
{
    return (std::forward<T>(t).*func)();
}

std::shared_ptr<T>がある場合は、次のようにexampleを呼び出します。

example(*my_shared_ptr, my_func); 
12
TartanLlama

std::shared_ptrはオーバーロードしないoperator ->*。オーバーロードを追加できます:

template <typename Ptr, typename MemberFunctor>
int example(std::shared_ptr<Ptr> ptr, MemberFunctor func )
{
    return (ptr.get()->*func)();
}
7
Jarod42