これは、ポインター(またはオブジェクトのようなポインター)とメンバー関数を取るテンプレート関数です。
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>'
どうして?と両方で動作するものを作るには?
std::shared_ptr
はサポートしていません pointer-to-memberアクセス演算子 (つまり、->*
および.*
)。そのため、->*
を直接指定してメンバー関数ポインターを呼び出すことはできません。呼び出し構文を変更して、operator*
およびoperator.*
を使用することができます。これは、生のポインターとスマートポインターの両方で機能します。
template <typename Ptr, typename MemberFunctor>
int example(Ptr ptr, MemberFunctor func )
{
return ((*ptr).*func)();
}
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)();
}
ただし、example
にT
への参照を取得させ、その上で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);
std::shared_ptr
はオーバーロードしないoperator ->*
。オーバーロードを追加できます:
template <typename Ptr, typename MemberFunctor>
int example(std::shared_ptr<Ptr> ptr, MemberFunctor func )
{
return (ptr.get()->*func)();
}