从指向模板函数的指针直接转换吗?

5
我试图获取一个指向函数模板实例的指针,并将其转换为void*:
#include <stdio.h>

void plainFunction(int *param) {}

template <typename T>
void templateFunction(T *param) {}

int main() {
    void *addr1=&plainFunction; //OK
    void *addr2=&templateFunction<int>; //Compile error
}

我在 Visual Studio 2008 中遇到了以下错误:
main.cu(10) : error C2440: 'initializing' : cannot convert from 'void (__cdecl *)(T *)' to 'void *'
Context does not allow for disambiguation of overloaded function

为什么会发生这种情况?函数templateFunction(具体类型为T=int)未被重载。可以推断出我所指的函数实例。
如果我用以下代码替换错误的行:
void (*foo)(int*)=&templateFunction<int>;
void *addr2=foo;

它可以编译成功。

谢谢!


更新:

当常规指针void*被虚拟函数指针void(*)()替换时,正如James所建议的那样(谢谢),这将使错误消失:

void (*addr1)()=(void(*)())&plainFunction;
void (*addr2)()=(void(*)())(&templateFunction<int>);

然而,如果错误是由于将函数指针转换为普通指针引起的,则编译器应在两种情况下报错。但实际上它并没有,所以我继续假设至少对于这个编译器来说是正确的。如果我没有错,标准只是说函数指针不必像普通指针一样表示,但并没有禁止这样做。


关于您的更新,函数指针和对象指针是否具有相同的大小和表示并不重要:从函数指针到void *的转换是不允许的。请注意,使用您的更新,您不能通过void(*)()调用任何一个函数,因为那不是任何一个函数的类型;您必须将addr1addr2强制转换回正确的类型(void(*)(int*))才能进行调用,否则行为是未定义的。 - James McNellis
我真正需要的是一个“函数入口点”,稍后将其传递给CUDA库。实际上,我正在获取指向从未存在为CPU可执行代码的函数指针,它驻留在GPU上。我只是剥离了CUDA特定的内容,以使我的示例尽可能简单,并从那些使用C++而不一定使用CUDA的人那里获得一些输入。我没有错 - 您的答案让我认识到了函数指针方面的问题,尽管我已经多次使用它们。谢谢。 - CygnusX1
2个回答

12

两种方法都不正确:在C++中,您不能将函数指针转换为void*

函数指针类型(例如此处的void (*)(int*))是与对象指针类型(例如此处的void*)完全不同的类型类别。

Visual C++即使允许进行转换(例如在void* addr1 = &plainFunction;中),这也是一种语言扩展。(编译时使用/Za标志禁用语言扩展会导致拒绝这两行代码。)

这个错误有点误导人,尽管其他一些编译器同样没有提供有用的信息(Comeau 报告“error: no instance of function template "templateFunction" matches the required type”)。


你是对的,虽然通常函数指针可以转换为普通函数。将问题更正以符合标准。 - CygnusX1
@CygnusX1:我不确定我理解你的评论。正如你所展示的,Visual C++确实允许你将函数模板实例的地址分配给函数指针。 - James McNellis
因为我的意思是“你是对的,虽然通常函数指针可以转换为普通指针”。是我的错。抱歉。我想一件事情,却写下了另一件事情。 - CygnusX1

6
编译器应在两种情况下生成错误。根据标准§4.10 / 2,函数指针不可转换为void*,因为函数不是对象(§1.8 / 1)。 Visual Studio 2008允许此作为扩展功能,请参阅此错误。使用typedef避免误解:
typedef void(func)(int*); // declare func type
func* addr1 = &plainFunction;         // OK
func* addr2 = &templateFunction<int>; // OK

哦,你的意思是将类型转换为void*是违反标准的,而不仅仅是“不必要,但可以”吗? - CygnusX1
1
“are not convertible” 意味着标准禁止这样做。VS2008 不是符合标准的编译器。如果您想保持代码的可移植性,就不应该使用 VS2008 中的该漏洞。 - Kirill V. Lyadvinsky
我之前不知道这实际上是一个 bug。现在我知道了。谢谢。 - CygnusX1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接