C-callback to function template:显式实例化模板
C-callback to function template: explicitly instantiate template
前提
我使用的是一个C库(来自C++(,它提供了以下接口:
void register_callback(void* f, void* data);
void invoke_callback();
问题
现在,我需要注册一个函数模板作为回调,这给我带来了问题。考虑以下代码:
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,但在编译器版本/平台的大多数其他组合上都有效(:
体系结构x86_64:的未定义符号
"void my_callback<int>(void*)", referenced from: _main in ccYLXc5w.o
我觉得这是可以理解的。
第一个"解决方案">
这很容易通过显式实例化模板来解决:
template void my_callback<int>(void* data);
不幸的是,这在我的真实代码中不适用,因为回调是在函数模板内注册的,而且我不知道该函数将被调用到哪组模板参数,所以我不能为所有这些参数提供显式实例化(我正在编程一个库(。所以我的真实代码看起来有点像这样:
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();
}
第二个"解决方案">
函数模板是通过调用函数来隐式实例化的。因此,让我们这样做,但要确保调用没有实际执行(该函数有副作用(:
template <typename T>
void do_register_callback(T& value) {
if (false) { my_callback<T>(0); }
register_callback(reinterpret_cast<void*>(my_callback<T>), &value);
}
即使启用了优化,这个似乎也能运行(这样编译器就可以删除死分支(。但我不确定这是否有一天会崩溃。我还发现这是一个非常丑陋的解决方案,需要一个长度解释性注释,以免将来的维护人员删除这些明显不必要的代码。
问题
如何实例化一个我不知道模板参数的模板这个问题显然是无稽之谈:我不能但是,有没有偷偷摸摸的办法?
除此之外,我的变通方法一定会成功吗
奖金问题
代码(特别是我将函数指针投射到void*
的事实(也会产生以下警告:
ISO C++禁止在指向函数的指针和指向对象的指针之间进行强制转换
当使用CCD_ 2进行编译时。我能在不为库编写强类型C包装的情况下以某种方式消除警告吗(在我的情况下这是不可能的(?
在ideone上运行代码(添加强制转换使其可编译(
显然,真正的问题是我的原始代码中缺少static_cast
register_callback(reinterpret_cast<void*>(&my_callback<int>), &ft);
此编译很好,但在使用GCC 4.5时会触发类似的错误。当使用GCC 4.2时,它甚至不进行编译,而是给出以下编译错误:
上下文信息不足,无法确定类型
一旦提供了这些"上下文信息",代码就会编译并链接:
register_callback(reinterpret_cast<void*>(
static_cast<void(*)(void*)>(my_callback<int>)), &value);
我不知道是否真的需要强制转换,也不知道(如果是的话(为什么GCC 4.5允许我放弃它,然后无法实例化模板。但至少我在不使用黑客的情况下编译了代码。
这应该有效:
template <typename T>
void do_register_callback(T& value) {
void (*callback)(void*) = my_callback<T>;
register_callback(reinterpret_cast<void*>(callback), &value);
}
第一行强制编译器实例化该函数以生成地址,然后您可以愉快地传递该地址
编辑:让我在这个组合中加入另一个选项。使my_callback
成为类模板的静态成员,如下所示:
template <typename T>
struct foo
{
static void my_callback(void* data) {
T& x = *static_cast<T*>(data);
std:: cout << "Call[T] with " << x << std::endl;
}
};
现在,在你的登记员中,你甚至不需要"演员阵容"。
template <typename T>
void do_register_callback(T& value) {
register_callback(reinterpret_cast<void*>(&foo<int>::my_callback), &value);
}
实例化类模板的规则似乎与函数模板不同——即,要获取类成员的地址,类型被实例化。
POSIX建议使用以下方法在函数指针类型和对象指针类型之间进行强制转换(在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++的代码可能是您的最佳选择。
- 从C++实例化QML
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 如何创建一个空的全局类并在启动时实例化它
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 约束和显式模板实例化
- 为什么包含windows.h会产生语法错误,从而阻止类的实例化?(C2146,C2065)
- 对象实例化调用构造函数的次数太多
- 如何使用非默认构造函数实例化模板化类
- 静态数据成员模板专用化的实例化点在哪里
- 错误的cv::face FacemarkLBF实例化
- C++的解析器在可以区分比较和模板实例化之前会做什么?
- 为什么 gcc 和 clang 为函数模板的实例化生成不同的符号名称?
- 检查某些类型是否是模板类 std::optional 的实例化
- 我有一个对象,它将在整个程序的持续时间内实例化,但一个类成员不会,我应该动态分配它吗?
- 无法使用 SWIG 在 Python 中实例化C++类(获取属性错误)
- 模板化类构造函数的模板实例化
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 受约束的成员函数和显式模板实例化
- 使用C++中的String To Class Lookup表来实例化类
- C-callback to function template:显式实例化模板