需要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));
但我不确定如何。在我的代码中,我开始得到一些非常冗长的postbind模板特化,它们开始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();
}
谢谢!
答案 0 :(得分:1)
您可以将模板专精移动到另一个类中,这样您就不必将它们放在postbind
的调用上。例如,创建一个空类,其目的是简单地保存所有长绘制的模板参数:
template<typename... Args>
struct post_bind_traits {};
现在代码中的其他位置(即另一个文件),您可以设置所需的所有参数版本。例如,在头文件中,您可以执行以下操作:
typedef post_bind_traits<int, int> pb_int_int;
typedef post_bind_traits<double, int> pb_double_int;
//... additional definitions
然后,您可以创建postbind
类的部分模板特化,如下所示:
template<typename... Args>
class postbind<post_bind_traits<Args...>> //add this partial specialization
{
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_;
};
现在您可以致电postbind
,前提是您可以访问标头文件中的typedef
定义,如下所示:
postbind<pb_int_int>::function func = postbind<pb_int_int>(/* arguments */);
在标题中打包所有复杂的typedefs
,您的主代码模块文件中的代码集会更清晰。
答案 1 :(得分:0)
我认为答案是没办法的。这是因为std :: function和std :: bind的返回值之间存在差异。
查看预期的调用std::function<void(...)> func = postbind(strand, std::bind(foo, myfoo(), 'a', _1);
。实际上,编译器只知道绑定的参数和一些占位符。一段时间后,调用它的operator(),然后未绑定的参数将替换占位符,现在编译器可以检查所有参数是否与函数签名匹配。
如果上述句子太难理解,请让我展示一些代码:
void foo(int) {}
foo(1); // Correct.
foo(1, 2); // Illegal, signature mismatched.
auto f = std::bind(foo, _1); // Here f has no idea about unbound args for foo.
f(1); // OK, 1 matches int.
f(1, 2); // OK too, although 2 is used.
f(1, 1, 1); // Same as before ones.
auto func = postbind(
strand, std::bind(foo, _1)); // If this is acceptable,
func(99); // this is a correct invocation then.
func(99, 98); // And this should also be happy for compiler. Ambiguity!
因此,您必须在绑定时明确指定签名。
但无论如何,这里有一段代码片段,我想这可能是替代解决方案:
template <typename... ArgTypes>
void do_post(strand_ptr strand, ArgTypes&&... args)
{
strand->post(std::bind(std::forward<ArgTypes>(args)...));
}
int main()
{
// some code
auto original_closure = std::bind(foo, myfoo(), 'a', _1);
auto final_closure = std::bind(
do_post<decltype(std::ref(original_closure)), int>, // signature deduced here
strand, std::ref(original_closure), _1); // std::ref used for inner std::bind
final_closure(99);
// others
}