Декораторы функций для std :: bind в C ++ 0x - PullRequest
0 голосов
/ 01 августа 2011

Мне нужна функция-обертка для std :: bind, которая будет вызываться перед функцией, которую она обернет, передавая аргументы обернутым функциям.

std::function<void (int)> foo = postbind<int>(service, handle);

Я дошел до этого

std::function<void (int)> foo = postbind(service, handle);

Как мне удалить этот параметр шаблона? Кажется, все сводится к выводу типа из функции генерации объекта (postbind), которая недостаточно умна.

#include <functional>

template<typename T>
void foo(std::function<void (T)> func)
{
}

void handler(int x)
{
}

int main()
{
    foo(handler);
    return 0;
}

Сообщает об ошибке: нет соответствующей функции для вызова 'foo (void (&) (int))'

Тем не менее, пример кода:

template<typename T>
void foo(T t)
{
}

int main()
{
    foo(99);
    return 0;
}

Это работает. Есть идеи, как сделать эту работу? Мне нужно иметь возможность передать ему std :: bind и успешно преобразовать результат в std :: function.

Как я могу удалить параметры шаблона? Спасибо.


Q. Что такое сервис и этот класс для этого?

а. Инкапсулируйте функцию-обертку, которая повышает :: asio :: io_service-> сообщения из текущего потока.


Полный исходный код:

#include <iostream>
#include <functional>
#include <memory>

class io_service
{
};

typedef std::shared_ptr<io_service> service_ptr;

template <typename Arg1>
class postbind_impl_1
{
public:
    typedef std::function<void (Arg1)> function;

    postbind_impl_1(service_ptr service, function memfunc)
      : service_(service), memfunc_(memfunc)
    {
    }

    void operator()(Arg1 arg1)
    {
        // do stuff using io_service
        memfunc_(arg1);
    }
private:
    service_ptr service_;
    function memfunc_;
};

template <typename Arg1>
postbind_impl_1<Arg1> postbind(service_ptr service, 
        typename postbind_impl_1<Arg1>::function handle)
{
    return postbind_impl_1<Arg1>(service, handle);
}

// ----------------

void handle(int x)
{
    std::cout << x << "\n";
}

int main()
{
    service_ptr service;
    std::function<void (int)> foo = postbind(service, handle);
    foo(110);
    return 0;
}

Ответы [ 4 ]

3 голосов
/ 02 августа 2011

Типы аргументов AFAICT выражения связывания не выводимы, поэтому то, что вы хотите, практически невозможно.

2 голосов
/ 01 августа 2011

Как вы ожидаете, что компилятор узнает, что будет использовать std::function?В этом коде:

#include <functional>

template<typename T>
void foo(T func)
{
}

void handler(int x)
{
}

int main()
{
    foo(handler);
    return 0;
}

T НЕ std::function<void (int)>.Это void (&)(int) (как сказано в сообщении об ошибке), ссылка на функцию, а не объект функтора.

Должно работать удержание типа аргумента переданной функции, попробуйте:

#include <functional>

template<typename T>
std::function<void (T)> foo(void (*func)(T))
{
}

void handler(int x)
{
}

int main()
{
    foo(handler);
    return 0;
}

Демо: http://ideone.com/NJCMS

Если вам нужно извлечь типы аргументов из std::function или простого указателя на функцию, вам понадобится вспомогательная структура:

template<typename>
struct getarg {};

template<typename TArg>
struct getarg<std::function<void (TArg)>> { typedef TArg type; };

template<typename TArg>
struct getarg<void (*)(TArg)> { typedef TArg type; };

template<typename TArg>
struct getarg<void (&)(TArg)> { typedef TArg type; };

template<typename T>
std::function<void (typename getarg<T>::type)> foo(T func)
{
}

void handler(int x)
{
}

int main()
{
    foo(handler);
    return 0;
}

Демо:http://ideone.com/jIzl7

С C ++ 0x вы также можете сопоставить все, что неявно преобразуется в std::function, включая возвращаемые значения из std::bind и лямбда-выражений: http://ideone.com/6pbCC

0 голосов
/ 18 марта 2012

Всем скептикам, которые сказали, что это невозможно:)

/*
 * Defines a function decorator ala Python
 *
 *   void foo(int x, int y);
 *   function<void ()> wrapper(function<void (int)> f);
 *
 *   auto f = decorator(wrapper, bind(foo, 110, _1));
 *   f();
 */

#include <functional>

template <typename Wrapper, typename Functor>
struct decorator_dispatch
{
    Wrapper wrapper;
    Functor functor;

    template <typename... Args>
    auto operator()(Args&&... args)
        -> decltype(wrapper(functor)(std::forward<Args>(args)...))
    {
        return wrapper(functor)(std::forward<Args>(args)...);
    }
};

template <typename Wrapper, typename Functor>
decorator_dispatch<
    Wrapper,
    typename std::decay<Functor>::type
>
decorator(Wrapper&& wrapper, Functor&& functor)
{
    return {wrapper, functor};
}
0 голосов
/ 01 августа 2011

Я не совсем уверен, чего вы пытаетесь достичь, но вот наивная оболочка, которая хранит список действий:

template <typename R, typename A>
struct wrap
{
  typedef std::function<R(A)> func;

  wrap(func f_) : f(f_) { }

  void prebind(func g) { prebound.push_back(g); }

  R operator()(A arg)
  {
    for (auto it = prebound.cbegin(); it != prebound.cend(); ++it)
    {
      func g = *it;
      g(arg);
    }

    f(arg);
  }
private:
  std::vector<func> prebound;
  func f;
};

wrap<void, int> make_wrap(std::function<void(int)> f)
{
  return wrap<void, int>(f);
}

Использование:

auto foowrap = make_wrap(foo);

foowrap.prebind(std::function<void(int)>(action1);
foowrap.prebind(std::function<void(int)>(action2);

foowrap(12);  // calls action1(12), action2(12), foo(12)
...