C++0x 中 std::bind 的函数装饰器
需要 std::bind 的函数包装器,它将在其包装器的函数之前调用,将参数传递给包装的函数。
std::function<void (int)> foo = postbind<int>(service, handle);
据我所知也是如此。我想让 postbind 对象自动推断类型。我尝试创建一个对象生成器 make_postbind(service, handle) 但它无法自动推断类型。
下面我写了一个测试用例。编译使用: g++ -o postbind postbind.cpp -std=c++0x -lboost_system
我想得到这一行:
std::function<void (int)> func = postbind<int>(strand, std::bind(foo, myfoo(), 'a', _1));
向下:
std::function<void (int)> func = postbind(strand, std::bind(foo, myfoo(), 'a', _1));
但我不确定如何。在我的代码中,我开始获得一些非常长的绑定后模板专业化,这些专业化开始 吃掉我的水平空白 :)
#include <boost/asio.hpp>
#include <thread>
#include <iostream>
#include <functional>
#include <memory>
using namespace boost::asio;
using std::shared_ptr;
typedef shared_ptr<io_service> service_ptr;
typedef shared_ptr<io_service::work> work_ptr;
typedef shared_ptr<io_service::strand> strand_ptr;
typedef std::shared_ptr<io_service::work> work_ptr;
using std::placeholders::_1;
template<typename... Args>
class postbind
{
public:
typedef std::function<void (Args...)> function;
postbind(strand_ptr strand, function memfunc)
: strand_(strand), memfunc_(memfunc)
{
}
void operator()(Args... params)
{
strand_->post(std::bind(memfunc_, std::forward<Args>(params)...));
}
private:
strand_ptr strand_;
function memfunc_;
};
// --------------------------------------------
struct myfoo
{
char a;
int b;
};
void run(service_ptr service)
{
service->run();
}
void foo(myfoo foo, char a, int x)
{
std::cout << "this thread: " << std::this_thread::get_id() << "\n"
<< x << "\n";
}
int main()
{
service_ptr service(new io_service);
strand_ptr strand(new io_service::strand(*service));
work_ptr work(new io_service::work(*service));
std::thread t(std::bind(run, service));
std::cout << "main thread: " << std::this_thread::get_id() << "\n";
std::function<void (int)> func = postbind<int>(strand, std::bind(foo, myfoo(), 'a', _1));
func(99);
t.join();
}
谢谢!
need a function wrapper for std::bind that will be called before the function it's wrapper, passing the arguments along to the wrapped functions.
std::function<void (int)> foo = postbind<int>(service, handle);
That's as far as I've got too. I'd like to make the postbind object auto-deduce the type. I've tried creating an object generator make_postbind(service, handle) but it was unable to deduce the types automatically.
Below I've written a test case. Compiles using: g++ -o postbind postbind.cpp -std=c++0x -lboost_system
I'd like to get the line:
std::function<void (int)> func = postbind<int>(strand, std::bind(foo, myfoo(), 'a', _1));
Down to:
std::function<void (int)> func = postbind(strand, std::bind(foo, myfoo(), 'a', _1));
But am unsure how to. In my code, I'm starting to get some really lengthy postbind template specialisations that are beginning to eat up my horizontal whitespace :)
#include <boost/asio.hpp>
#include <thread>
#include <iostream>
#include <functional>
#include <memory>
using namespace boost::asio;
using std::shared_ptr;
typedef shared_ptr<io_service> service_ptr;
typedef shared_ptr<io_service::work> work_ptr;
typedef shared_ptr<io_service::strand> strand_ptr;
typedef std::shared_ptr<io_service::work> work_ptr;
using std::placeholders::_1;
template<typename... Args>
class postbind
{
public:
typedef std::function<void (Args...)> function;
postbind(strand_ptr strand, function memfunc)
: strand_(strand), memfunc_(memfunc)
{
}
void operator()(Args... params)
{
strand_->post(std::bind(memfunc_, std::forward<Args>(params)...));
}
private:
strand_ptr strand_;
function memfunc_;
};
// --------------------------------------------
struct myfoo
{
char a;
int b;
};
void run(service_ptr service)
{
service->run();
}
void foo(myfoo foo, char a, int x)
{
std::cout << "this thread: " << std::this_thread::get_id() << "\n"
<< x << "\n";
}
int main()
{
service_ptr service(new io_service);
strand_ptr strand(new io_service::strand(*service));
work_ptr work(new io_service::work(*service));
std::thread t(std::bind(run, service));
std::cout << "main thread: " << std::this_thread::get_id() << "\n";
std::function<void (int)> func = postbind<int>(strand, std::bind(foo, myfoo(), 'a', _1));
func(99);
t.join();
}
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以将模板专业化移到另一个类中,这样您就不必将它们放在对
postbind
的调用中。例如,创建一个空类,其目的是简单地保存所有冗长的模板参数:现在,在代码的其他位置(即另一个文件),您可以设置所需的所有参数版本。例如,在头文件中,您可以执行以下操作:
然后您可以创建
postbind
类的部分模板专业化,如下所示:现在您可以调用
postbind
,前提是您可以访问头文件中的typedef
定义,如下所示:将所有复杂的
typedef
打包到头文件中,您将获得更清晰的代码- 在主代码模块文件中设置。You could move your template specializations into another class so that you do not have to place them on your calls to
postbind
. For instance, create an empty class who's purpose is to simply hold all the long drawn-out template arguments:Now somewhere else in your code (i.e., another file), you could setup all the versions of arguments you would need. For instance, in a header file you could do the following:
Then you can create a partial template specialization of your
postbind
class that looks like the following:Now you can call
postbind
, provided you have access to thetypedef
definitions in the header files, like the following:Pack all the complicated
typedefs
in your header, and you'll have a much cleaner code-set in your main code-module files.我想答案是没有办法。这是因为 std::function 和 std::bind 的返回值之间的差异。
查看预期的调用,
std::functionfunc = postbind(strand, std::bind(foo, myfoo(), 'a', _1);
。实际上,编译器只知道绑定的参数和一些占位符。过了一会儿,它的operator()被调用,那么未绑定的参数将替换占位符,现在编译器可以检查所有参数是否与函数签名匹配。如果上面的句子太深奥难以理解,请让我展示一些代码:
结果,你。 但无论如何
,这里的代码片段可能是我猜的替代解决方案:
I think the answer is no way. This is because of the difference between std::function and the return value of std::bind.
Look at the expected invocation,
std::function<void(...)> func = postbind(strand, std::bind(foo, myfoo(), 'a', _1);
. Actually, the compiler only knows the bound arguments and some placeholders. After a while, its operator() is invoked, then the unbound arguments are going to replace the placeholders, and now compiler can check whether all arguments matches the function signature or not.If above sentences are too recondite to understand, please let me show some code:
As a result, you have to specify the signature explicitly while binding.
But anyway, here's a code snippet which might be a substitute solution I guess: