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)
See Question&Answers more detail:
os