我有一个函数指针表,我正在尝试确定定义函数签名的顺序是否重要。看看我下面的例子,我想知道为什么 Method 1
不能编译,即使它的函数指针类型可以通过 decltype 确定。我想知道如何才能使 Method 1
工作。有任何想法吗?谢谢。
// Method 1
typedef struct FOO_FUNCS
{
void( WINAPI * pfnFoo) ();
} FOO_FUNCS;
typedef decltype(&FOO_FUNCS::pfnFoo) PFN_FOO;
// Method 2
typedef void (WINAPI* PFN_BAR)();
typedef struct BAR_FUNCS
{
PFN_BAR pfnBar;
} BAR_FUNCS;
class FooBarClass
{
public:
static void WINAPI Foo()
{
cout << "Foo" << "\n";
}
static void WINAPI Bar()
{
cout << "Bar" << "\n";
}
};
int _tmain(int argc, _TCHAR* argv[])
{
void* pfnFoo = reinterpret_cast<void*>(FooBarClass::Foo);
reinterpret_cast<PFN_FOO>(pfnFoo) (); <= = this gives me "error C2440 : 'reinterpret_cast' : cannot convert from 'void *' to 'PFN_FOO'"
void* pfnBar = reinterpret_cast<void*>(FooBarClass::Bar);
reinterpret_cast<PFN_BAR>(pfnBar) ();
}
最佳答案
展开typedefs和decltype后,PFN_FOO
是 FOO_FUNCS
的成员指针 ,成员的类型是指向 void WINAPI ()
的指针.您不能在指向成员的指针和 void*
之间进行转换.这就是您收到错误的原因。
我不确定,但我相信您可能一直在寻找其中之一:
typedef decltype(FOO_FUNCS().pfnFoo) PFN_FOO;
typedef decltype(&FOO_FUNCS().pfnFoo) PFN_FOO;
(在一般情况下,您更愿意使用 std::declval<FOO_FUNCS>()
而不是上面的 FOO_FUNCS()
,因为它不需要可访问的默认构造函数)。
或者也许是最简单的(感谢@Jarod42):
typedef decltype(FOO_FUNS::pfnFoo) PFN_FOO;
下面是每个 typedef 更详细的作用:
decltype(FOO_FUNCS().pfnFoo)
表达式是FOO_FUNCS().pfnFoo
.即创建一个默认构造的FOO_FUNCS
对象并访问其数据成员 pfnFoo
. decltype()
应用于这样的表达式会产生数据成员的类型,即 void( WINAPI * ) ()
.这是一个指向 WINAPI
的指针函数不带参数并返回 void
.
decltype(&FOO_FUNCS().pfnFoo)
表达式是&FOO_FUNCS().pfnFoo
.即创建一个默认构造的FOO_FUNCS
对象,访问其数据成员 pfnFoo
并获取它的地址(在内存中)。 this 的类型是“指向 pfnFoo
类型的指针;”这意味着这个 decltype 等同于 decltype(FOO_FUNCS().pfnFoo) *
.所以它是void( WINAPI * * ) ()
- 指向 WINAPI
的指针函数不带参数并返回 void
.
decltype(FOO_FUNCS::pfnFoo)
表达式是FOO_FUNCS::pfnFoo
.即,将数据成员命名为pfnFoo
类FOO_FUNCS
. decltype()
产生该数据成员的类型,又是 void( WINAPI * ) ()
- 指向 WINAPI
的指针函数不带参数并返回 void
.
还有你原来的:
decltype(&FOO_FUNCS::pfnFoo)
表达式是&FOO_FUNCS::pfnFoo
.也就是说,取指向成员的指针(有时不准确地称为“成员指针”)pfnFoo
类FOO_FUNCS
.类型是 void (WINAPI (FOO_FUNCS::*)*) ()
- 指向类成员的指针 FOO_FUNCS
,其中成员具有指向 WINAPI
的类型指针函数不带参数并返回 void
.
最后一个是根本不同的 - 另一个只是尝试以不同的方式访问成员作为变量(通过临时,通过限定名称),如果你愿意的话,这是一 block 物理内存。最后一个将其视为“逻辑”成员,作为类中的“偏移量”。这与指针 ( T*
) 和指向类 X
成员的指针之间的根本区别相同。 (T X::*
)。
关于c++ - C++ 中函数签名的定义顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23866377/