I have a table of function pointers, and I am trying to determine whether the order of defining the function signatures matters. Looking at my example below, I am wondering why Method 1
doesn't compile, even though its function pointer type can be determined via decltype. I'd like to know what can be done to make Method 1
work. Any ideas? Thanks.
// 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) ();
}
After expanding typedefs and decltype, PFN_FOO
is a pointer to member of FOO_FUNCS
, the type of the member being pointer to void WINAPI ()
. You cannot convert between a pointer to member and a void*
. That's why you're getting the error.
I am not sure, but I believe you may have been looking for one of these:
typedef decltype(FOO_FUNCS().pfnFoo) PFN_FOO;
typedef decltype(&FOO_FUNCS().pfnFoo) PFN_FOO;
(In the general case, you'd prefer to use std::declval<FOO_FUNCS>()
instead of just FOO_FUNCS()
in the above, since that does not require an accessible default constructor).
Or perhaps the simplest (thanks to @Jarod42):
typedef decltype(FOO_FUNS::pfnFoo) PFN_FOO;
Here is what each of the typedefs does in more detail:
decltype(FOO_FUNCS().pfnFoo)
The expression is FOO_FUNCS().pfnFoo
. That is, create a default-constructed FOO_FUNCS
object and access its data member pfnFoo
. decltype()
applied to such an expression yields the type of the data member, which is void( WINAPI * ) ()
. That's a pointer to a WINAPI
function taking no parameters and returning void
.
decltype(&FOO_FUNCS().pfnFoo)
The expression is &FOO_FUNCS().pfnFoo
. That is, create a default-constructed FOO_FUNCS
object, access its data member pfnFoo
and get its address (in memory). The type of this is "pointer to type of pfnFoo
;" that means this decltype is equivalent to decltype(FOO_FUNCS().pfnFoo) *
. So it's void( WINAPI * * ) ()
- a pointer to a pointer to a WINAPI
function taking no parameters and returning void
.
decltype(FOO_FUNCS::pfnFoo)
The expression is FOO_FUNCS::pfnFoo
. That is, name the data member pfnFoo
of class FOO_FUNCS
. decltype()
yields the type of this data member, which is again void( WINAPI * ) ()
- a pointer to a WINAPI
function taking no parameters and returning void
.
And your original one:
decltype(&FOO_FUNCS::pfnFoo)
The expression is &FOO_FUNCS::pfnFoo
. That is, take the pointer to member (sometimes imprecisely called "member pointer") pfnFoo
of class FOO_FUNCS
. The type is void (WINAPI (FOO_FUNCS::*)*) ()
- a pointer to member of class FOO_FUNCS
, where the member has type pointer to a WINAPI
function taking no parameters and returning void
.
The last one is fundamentally different - the other just play around with different ways of accessing the member as a variable (through a temporary, through qualified name), a physical piece of memory if you will. The last one treats it as a "logical" member, as an "offset" within the class. It's the same fundamental difference as between a pointer (T*
) and a pointer to member of class X
(T X::*
).
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments