C回调到功能模板:显式实例化模板 [英] C-callback to function template: explicitly instantiate template
问题描述
我正在使用C库(来自C ++),该库提供以下接口:
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();
}
这给了我以下链接器错误(在OS X上使用g ++(GCC)4.5.1 ,但可以在大多数其他编译器版本/平台组合上使用):
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):
x86_64体系结构的未定义符号:
Undefined symbols for architecture x86_64:
"void my_callback<int>(void*)", referenced from:
_main in ccYLXc5w.o
我认为是可以理解的.
可以通过显式实例化模板来轻松解决此问题:
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.
如何实例化一个我不知道其模板参数的模板?这个问题显然是胡说:我不能. –但是这有偷偷摸摸的方法吗?
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?
除非,我的解决方法是否一定能成功?
代码(特别是我将函数指针转换为void*
的事实)也会产生以下警告:
The code (specifically, the fact that I cast a function pointer to void*
) also produces the following warning:
ISO C ++禁止在指针指向函数和指针指向对象之间进行强制转换
ISO C++ forbids casting between pointer-to-function and pointer-to-object
当使用-pedantic
进行编译时.我可以以某种方式摆脱警告,而不必为该库编写一个强类型的C包装器(在我的情况下这是不可能的)吗?
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)?
在ideone上运行代码 (并添加了强制转换以使其可编译)
Running code on ideone (with an added cast to make it compile)
推荐答案
POSIX建议采用以下方法在函数指针类型和对象指针类型(在C99中未定义)之间进行转换:
POSIX recommends the following way to cast between function pointer types and object pointer types (which is undefined in C99):
typedef void function_type(void*);
function_type *p_to_function = &my_callback<T>;
void* p_to_data = *(void**)&p_to_function;
// Undefined:
// void* p_to_data = (void*)p_to_function;
请注意,在C ++领域,这将从function_type**
执行reinterpret_cast<void**>(&p_to_function)
.与reinterpret_cast<void*>(p_to_function)
不同,这不是不确定的,而是实现定义的.因此,编写依赖于实现的符合C ++的代码可能是最好的选择.
Notice that in C++-land, this would perform a reinterpret_cast<void**>(&p_to_function)
from function_type**
. This is not undefined but instead implementation-defined, unlike reinterpret_cast<void*>(p_to_function)
. So it's probably your best bet to write C++-conformant code that relies on the implementation.
这篇关于C回调到功能模板:显式实例化模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!