I have a template member function with this signature:
template<typename T> void sync(void (*work)(T*), T context);
It can be called with a pointer to a function that accepts an argument of type T*
. context
is passed to that function. The implementation is this:
template<typename T> void queue::sync(void (*work)(T*), T context) {
dispatch_sync_f(_c_queue, static_cast<void*>(&context),
reinterpret_cast<dispatch_function_t>(work));
}
It uses reinterpret_cast<>
and it works. The problem is that the standard doesn't define it very well and it is very dangerous. How can I get rid of this? I tried static_cast
but that gave me a compiler error:
static_cast
fromvoid (*)(std::__1::basic_string<char> *)
todispatch_function_t
(akavoid (*)(void *)
) is not allowed.
dispatch_function_t
is a C type and is the same as void (*)(void*)
.
I'm not sure I was clear enough. What dispatch_sync_f
does is it calls a given callback function and passes the given context parameter to that callback function. (It does that on another thread, although that is out of the scope of this question.)
The reason this is not supported by static_cast
is because it is
potentially unsafe. While a std::string*
will convert implicitely to
a void*
, the two are not the same thing. The correct solution is to
provide a simple wrapper class to your function, which takes a void*
,
and static_cast
s it back to the desired type, and pass the address of
this wrapper function to your function. (In practice, on modern
machines, you'll get away with the reinterpret_cast
, since all
pointers to data have the same size and format. Whether you want to cut
corners like this is up to you—but there are cases where it's
justified. I'm just not convinced that this is one of them, given the
simple work-around.)
EDIT: One additional point: you say that dispatch_function_t
is a C type. If this is the case, the actual type if probably extern "C" void (*)(void*)
, and you can only initialize it with functions that have "C"
linkage. (Again, you're likely to get away with it, but I've used compilers where the calling conventions were different for "C"
and "C++"
.)