2

最近、メンバー関数をオブジェクトのインスタンスにバインドすることがよくあります。std::bind、std::mem_fn、および std::ref を組み合わせて使用​​するのではなく、これらすべてを 1 つの関数に組み合わせて、すべてを自動的に処理したいと考えています。

たとえば、次のコードを考えてみましょう。

#include <functional>
#include <iostream>
#include <string>

// This is the function I'd like to have working:
template <class T, typename RETURN_TYPE, typename... Arguments>
std::function<RETURN_TYPE(Arguments...)> obj_bind(RETURN_TYPE (T::*in_fun)(), T & obj, Arguments... params)
{
  return std::bind( std::mem_fn(in_fun), std::ref(obj), params...);
}

int main()
{
  // Standard use of push_back member function (our test case):
  std::string test_obj = "Test 1: ";
  test_obj.push_back('A');
  std::cout << test_obj << std::endl;

  // This WORKS:
  auto test_fun = std::bind( std::mem_fn(&std::string::push_back), std::ref(test_obj), 'B');

  // But I'd like to use this instead:
  // auto test_fun = obj_bind( &std::string::push_back, test_obj, 'C');

  test_obj = "Test 2: ";
  test_fun();
  std::cout << test_obj << std::endl;
}

私の obj_bind 関数は実際には引数のないメンバー関数でうまく動作するので、私の問題はそれらの処理方法にあると確信していますが、修正に何度か失敗した後、ここでアドバイスを求めてみようと思いました.

4

1 に答える 1

2

バインダーの修正に入る前に、いくつかの注意事項があります。

  1. メンバー関数ポインターの処理方法は既にわかっているためstd::mem_fn()、最初の引数に使用する必要はありません。std::bind()std::bind()
  2. メンバー関数のアドレスを取る型は未定義です。つまり、std::string::push_back引数を 1 つだけ取るメンバ関数ポインタになることはできません。
  3. 使用する代わりに、std::ref(testobj)jut juse を使用できます&testobj

引数が必要な場合、このようなメンバー関数を推測することはできません: 引数を指定する必要があります:

template <class T, typename RETURN_TYPE, typename...Args, typename... Arguments>
std::function<RETURN_TYPE(Arguments...)>
obj_bind(RETURN_TYPE (T::*in_fun)(Args...), T & obj, Arguments... params) {
    ...
}

これにより、即時のエラーを乗り越えることができます。次の問題は、バインドされた引数を呼び出される関数の型に関連付けたことです。もちろん、それはそれがどのように機能するかではありません。あなたの場合、結果の引数は実際には引数を取りません。つまり、次のような宣言があります。

template <class T, typename RETURN_TYPE, typename... Args, typename... Arguments>
std::function<RETURN_TYPE()>
obj_bind(RETURN_TYPE (T::*in_fun)(Args...), T & obj, Arguments... params) {
    ...
}

関数で実際にプレースホルダーを使用する場合、返さstd::function<RC(...)>れるものは実際には何らかの引数を取ります。これらの議論を理解することは、やや自明ではありません。ただし、引数の型を関数へのポインターまたはメンバー関数へのポインターに制限する場合は、適切な関数オブジェクトを返すことができるはずです。

楽しみのために、プレースホルダーを扱うように見える実装を次に示します (ただし、完全にはテストされていません)。

#include <functional>
#include <iostream>
#include <string>

using namespace std::placeholders;

struct foo
{
    void f(int i, double d, char c) {
        std::cout << "f(int=" << i << ", double=" << d << ", char=" << c << ")\n";
    }
};

template <typename...> struct type_list;

template <typename, typename, typename, typename> struct objbind_result_type;
template <typename RC, typename... RA>
struct objbind_result_type<RC, type_list<RA...>, type_list<>, type_list<> > {
    typedef std::function<RC(RA...)> type;
};

template <typename RC,
          typename... RA,
          typename A0, typename... A,
          typename B0, typename... B>
struct objbind_result_type<RC, type_list<RA...>,
                           type_list<A0, A...>,
                           type_list<B0, B...> >;

template <bool, typename, typename, typename, typename, typename>
struct objbind_result_type_helper;
template <typename A0, typename RC, typename... RA, typename... A, typename...B>
struct objbind_result_type_helper<true, A0, RC, type_list<RA...>, type_list<A...>, type_list<B...> > {
    typedef typename objbind_result_type<RC, type_list<RA..., A0>, type_list<A...>, type_list<B...> >::type type;
};

template <typename A0, typename RC, typename... RA, typename... A, typename...B>
struct objbind_result_type_helper<false, A0, RC, type_list<RA...>, type_list<A...>, type_list<B...> > {
    typedef typename objbind_result_type<RC, type_list<RA...>, type_list<A...>, type_list<B...> >::type type;
};

template <typename RC,
          typename... RA,
          typename A0, typename... A,
          typename B0, typename... B>
struct objbind_result_type<RC, type_list<RA...>,
                           type_list<A0, A...>,
                           type_list<B0, B...> > {
    typedef typename objbind_result_type_helper<bool(std::is_placeholder<B0>::value), A0,
                                                RC, type_list<RA...>,
                                                type_list<A...>,
                                                type_list<B...> >::type type;
};


// This is the function I'd like to have working:
template <class T, typename RETURN_TYPE, typename...Args, typename... Arguments>
typename objbind_result_type<RETURN_TYPE, type_list<>, type_list<Args...>, type_list<Arguments...> >::type
obj_bind(RETURN_TYPE (T::*in_fun)(Args...), T & obj, Arguments... params)
{
  return std::bind(in_fun, &obj, params...);
}

int main()
{
  foo fo;
  auto fun = obj_bind(&foo::f, fo, _1, 2.34, _2);
  fun(17, 'b');
}
于 2014-12-07T21:24:01.017 に答える