Premise
I’m using a C library (from C++) which provides the following interface:
void register_callback(void* f, void* data);
void invoke_callback();
Problem
Now, I need to register a function template as a callback and this is causing me problems. Consider the following code:
template <typename T> void my_callback(void* data) { … }
int main() {
int ft = 42;
register_callback(reinterpret_cast<void*>(&my_callback<int>), &ft);
invoke_callback();
}
This gives me the following linker error (using g++ (GCC) 4.5.1 on OS X but works on most other combinations of compiler version / platform):
Undefined symbols for architecture x86_64:
"void my_callback<int>(void*)", referenced from: _main in ccYLXc5w.o
which I find understandable.
First “solution”
This is easily fixed by explicitly instantiating the template:
template void my_callback<int>(void* data);
Unfortunately, this isn’t applicable in my real code since the callback is registered inside a function template, and I don’t know for which set of template arguments this function will be called, so I can’t provide explicit instantiations for all of them (I’m programming a library). So my real code looks a bit like this:
template <typename T>
void do_register_callback(T& value) {
register_callback(reinterpret_cast<void*>(my_callback<T>), &value);
// Other things …
}
int main() {
int ft = 42;
do_register_callback(ft);
invoke_callback();
}
Second “solution”
A function template is implicitly instantiated by calling the function. So let’s do that, but make sure that the call isn’t actually performed (the function has got side-effects):
template <typename T>
void do_register_callback(T& value) {
if (false) { my_callback<T>(0); }
register_callback(reinterpret_cast<void*>(my_callback<T>), &value);
}
This seems to work, even with optimisations enabled (so that the dead branch is removed by the compiler). But I’m not sure if this won’t some day break down. I also find this a very ugly solution that requires a length explanatory comment lest some future maintainer remove this obviously unnecessary code.
Question
How do I instantiate a template for which I don’t know the template arguments? This question is obviously nonsense: I can’t. – But is there a sneaky way around this?
Barring that, is my workaround guaranteed to succeed?
Bonus question
The code (specifically, the fact that I cast a function pointer to void*
) also produces the following warning:
ISO C++ forbids casting between pointer-to-function and pointer-to-object
when compiling with -pedantic
. Can I somehow get rid of the warning, without writing a strongly-typed C wrapper for the library (which is impossible in my situation)?
Running code on ideone (with an added cast to make it compile)
if(false)
is redundant - as thestatic_cast
forces instantiation anyway. – Ruizvoid (*)(void*)
in register callback? – Polychromyif(false) { my_callback<T>(value); }
instead of assuming that all callbacks will use pointer values? It's at least slightly less ugly. – Gabriellegabriellivoid*
, I guess it will always use a pointer argument. – Frymire(void *)
instead ofreinterpret_cast<void *>
may get rid of the warning. If it doesn't you could always use a union. – GabriellegabrielliNULL
instead of a raw 0. It's possible to pass a number as a pointer, reinterpreting the pointer value as an integer, but since the OP's code is shown passing a poInter to anint
it does seem unlikely. Oh well, everyone misreads sometimes. – Gabriellegabriellistatic_cast
or areinterpret_cast
(or something else which I forgot but which doesn’t apply here). The cast is still being performed. – Threnode