我正在尝试为 std::bind 编写一个包装器。 我的第一个尝试是:
typedef std::function<void(float, int)> tCallback;
template<typename F, class... Args>
tCallback mybind(F f, Args... args)
{
return std::tr1::bind( f, Args... args,
std::tr1::placeholders::_1, std::tr1::placeholders::_2 );
}
给定如下内容:
struct Foo {
tCallback m__cb;
setcb(tCallback cb) {m_cb = cb;}
....
};
void f1(float f, int i) {}
void f2(int j, float f, int i) {}
Foo foo;
foo.setcb( mybind( f1 ) ); // Fine.
foo.setcb( mybind( f2, 1 ) ); // Not fine.
我做错了什么? 在Visual Studio上,错误指的是以"int &"开头的Args(这让我感到惊讶,但我可能会看到几层错误消息(。 在GCC上,错误是指"参数太多"。 (我不会天真到期望来自像这样的深度模板化代码的有用错误消息!
我是否需要为函数指针和成员函数指针编写 mybind 版本(以及我该如何处理函子(?
注意:我使用的是VS2015和GCC 4.9,因此std::bound和占位符在tr1中。
由于Args... args
,您会收到错误,正如评论中已经提到的应该只是args...
。
还要考虑使用 std::forward
正确转发参数和更喜欢使用 decltype
来确定包装函数的返回类型这不会强制转换为std::function
:
#include <functional>
typedef std::function<void(float, int)> tCallback;
template<typename F, typename... Args>
auto mybind(F f, Args... args)
-> decltype(std::bind(std::forward<F>(f), std::forward<Args>(args)...,
std::placeholders::_1, std::placeholders::_2 ))
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
return std::bind(std::forward<F>(f), std::forward<Args>(args)...,
// ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~~~
std::placeholders::_1, std::placeholders::_2 );
}
struct Foo {
tCallback m_cb;
void setcb(tCallback cb) {m_cb = cb;}
};
void f1(float f, int i) {}
void f2(int j, float f, int i) {}
int main()
{
Foo foo;
foo.setcb( mybind( f1 ) ); // Fine.
foo.setcb( mybind( f2, 1 ) ); // Not fine.
}
演示
只是关于笔记的快速说明:-(
注意:我使用的是VS2015和GCC 4.9,因此std::bound和占位符在tr1中。
std::bind
已从 Visual Studio 2013(2012( 移动到 std 命名空间中,并且应优先于 tr1 命名空间。
所以实际的问题是
return std::tr1::bind( f, Args... args,
std::tr1::placeholders::_1, std::tr1::placeholders::_2 );
实际上是:
return std::tr1::bind( f, args...,
std::tr1::placeholders::_1,
std::tr1::placeholders::_2, std::tr1::placeholders::_2 );
"Args... args" vs "args..." 是我记错了代码。 双倍的 _2 意味着我试图调用一个参数数量错误的函数。 (我不明白为什么它适用于零绑定参数,但这是一个不同的问题!