恒常性に関係なくメソッドへのポインタを取る関数
オブジェクトへの参照とそのメンバー関数へのポインターを受け取り、それを呼び出すジェネリック関数を実装したいと思います。ただし、クラスにconstメソッドとnon-constメソッドの両方がある場合、2つのオーバーロードを提供する必要があるため、これを行うことはできません。
template<typename Ret, typename Class, typename ...Us>
Ret callMethod(Class &object, Ret (Class::*method)(Us...))
{
return (object.*method)(Us{}...);
}
template<typename Ret, typename Class, typename ...Us>
Ret callMethod(Class &object, Ret (Class::*method)(Us...) const)
{
return (object.*method)(Us{}...);
}
constメソッドポインターとnon-constメソッドポインターの両方を受け入れるテンプレート関数を1つだけ記述する方法があるので、コードを2回記述する必要はありませんか?私はC ++ 14を使用しています。
より広い視野で、私が最終的に達成したいのは、メソッド引数が抽出されるデータバッファーである3番目のパラメーターを渡すことです。したがって、テンプレート関数はそれを可能な限り一般的に処理します。
回答
これは、を使用しないC ++ 14の代替手段std::function
です。
私が最終的に達成したいのは、メソッド引数が抽出されるデータバッファーである3番目のパラメーターを渡すことです。したがって、テンプレート関数はそれを可能な限り一般的に処理します。
コールサイトで使用するものは、ここに完全に転送されます。
template<typename Class, typename Func, typename... Args>
decltype(auto) callMethod_impl(Class& object, Func method, Args&&... args) {
return (object.*method)(std::forward<Args>(args)...);
}
template<typename Ret, typename Class, typename... Us, typename... Args>
Ret callMethod(Class& object, Ret(Class::*method)(Us...), Args&&... args) {
return callMethod_impl(object, method, std::forward<Args>(args)...);
}
template<typename Ret, typename Class, typename... Us, typename... Args>
Ret callMethod(const Class& object, Ret(Class::*method)(Us...) const, Args&&... args) {
return callMethod_impl(object, method, std::forward<Args>(args)...);
}
デモ
あなたが必要な場合Ret
にはcallMethod_impl
、単にテンプレートパラメータとして追加し、同じようにそれを呼び出すcallMethod_impl<Ret>(...)
からcallMethod
過負荷(デモ)。
簡単に言うと、これを自分で実装しないでください。すでに次の形式で実装されていますstd::invoke。
#include <functional>
struct A {
void foo(int x);
void bar(int x) const;
};
void example() {
A a;
std::invoke(&A::foo, a, 3);
std::invoke(&A::bar, a, 3);
}
振り返ってみると、C ++ 14タグを追加したことを確認すると、のドキュメントにstd::invokeは、プロジェクトで使用できるサンプル実装があります。
がないとstd::invoke
、型消去に基づいて、多かれ少なかれ一般的な回避策しか実行できません。を使用std::function
すると、関数を同等に扱うプロキシ関数を作成できます。
#include <iostream>
#include <functional>
template<typename Ret, typename ...Us>
Ret callMethod_impl(std::function<Ret(Us...)> f) {
// common implementation here
return f(Us{}...);
}
template<typename Ret, typename Class, typename ...Us>
Ret callMethod(Class &object, Ret (Class::*method)(Us...)) {
return callMethod_impl(std::function<Ret(Us...)>(std::bind(method, object)));
}
template<typename Ret, typename Class, typename ...Us>
Ret callMethod(const Class &object, Ret (Class::*method)(Us...) const) {
return callMethod_impl(std::function<Ret(Us...)>(std::bind(method, object)));
}
struct Foo {
int bar() const { return 1; }
float bar() { return 2.1f; };
};
int main() {
Foo f;
std::cout << callMethod(f, &Foo::bar) << std::endl;
}
ここではvolatile
関数(+の組み合わせ)は扱われていませんが、完全な一般性ではなく、実用的なソリューションが必要な場合があることに注意してください。