I have a two-layer object structure where the contained object has a deadline_timer and the outer object has the handler function, as:
class Internal
{
asio::deadline_timer t;
public:
void QueueTick(void (*handler)(boost::system::error_code const&))
{
t.expires_from_now(posix_time::millisec(250));
t.async_wait(handler);
}
};
class ForClients
{
Internal I;
void OnTick(boost::system::error_code const&) { /*...*/ }
void Init()
{
I.QueueTick(boost::bind(&cdevXcite::OnTick, this, _1));
}
};
The QueueTick()
call is failing to compile in MSVS 2008 with "cannot convert parameter 1 from 'boost::_bi::bind_t' to 'void (__cdecl *)(const boost::system::error_code &)'".
If I make the timer member public and make a direct call to I.t.async_wait()
with the same argument, it succeeds. Clearly, the handler's signature is more special than what I've used in the QueueTick
declaration; however, I can't find a symbol that defines it and I don't know how to interpret the metaprogramming going on inside the basic_deadline_timer<>
template.
An asio timer's async_wait
can be called with any callable type that can be called with a boost::system::error_code const&
argument. There isn't a single type anywhere that defines it, it just has to be callable with the documented argument type.
The type of your QueueTick parameter is one such callable type, a pointer to a plain ol' non-member function with the right signature:
void QueueTick(void (*handler)(boost::system::error_code const&))
But the result of boost::bind
is a class type with an overloaded operator()
which is not convertible to that function pointer type.
There are a few ways to solve this, but the simplest is probably to follow async_wait
itself and write QueueTick as a function template, accepting any type:
class Internal
{
asio::deadline_timer t;
public:
template<WaitHandle>
void QueueTick(WaitHandle handler)
{
t.expires_from_now(posix_time::millisec(250));
t.async_wait(handler);
}
};
The rest of the code would be unchanged.
If that's not an option (e.g. because QueueTick needs to be virtual) then you could use boost::function
with can hold any callable object of the right signature:
class Internal
{
asio::deadline_timer t;
public:
typedef boost::function<void(boost::system::error_code const&)> handler_type;
void QueueTick(handler_type handler)
{
t.expires_from_now(posix_time::millisec(250));
t.async_wait(handler);
}
};
This will have a small overhead compared to the template version, due to constructing the boost::function
object.