C ++ 0x中std :: bind的函数装饰器

时间:2011-08-01 15:05:38

标签: templates functional-programming c++11 bind decorator

我需要一个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(&amp;)(int))'

然而,代码示例:

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

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

这很有效。任何想法如何使这项工作?我需要能够将std :: bind传递给它并将结果成功转换为std :: function。

如何删除模板参数?感谢。


Q值。什么是服务,本课程意味着什么?

一个。封装一个函数包装器,它将boost :: asio :: io_service-&gt;发布到当前线程之外。


完整源代码:

#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 个答案:

答案 0 :(得分:3)

绑定表达式的AFAICT参数类型是不可推导的,所以你想要的几乎是不可能的。

答案 1 :(得分:2)

您希望编译器如何知道使用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和lambdas的返回值:http://ideone.com/6pbCC

答案 2 :(得分:0)

我不完全确定你想要实现的目标,但这是一个存储行动列表的天真包装:

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)

答案 3 :(得分:0)

对所有说不可能的反对者:)

/*
 * 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};
}