So the following code works great:
void function() { }
std::cout << typeid(decltype(function)).name() << '\n';
but the following code doesn't compile:
struct object {
void function() { }
}
std::cout << typeid(decltype(object::function)).name() << '\n';
Why?
The member function has a type, just as the normal function has a type right? I would assume it looks like this:
void func(object*, void)
The strange thing is, I can get the pointer just fine with:
decltype(&object::function)
That ends up being this:
void (__thiscall object::*)(void)
If I can get the pointer to it, why can't I get the type of it? Just like I can with the normal function. I tried to remove the pointer after getting the pointer to member function type:
template <typename T>
struct remove_pointer { using type = T; }
template <typename T>
struct remove_pointer<T object::*> { using type = T; }
std::cout << typeid(remove_pointer<decltype(&object::function)>::type).name() << '\n';
That removes the pointer just fine, so why doesn't decltype just let me do it directly? Why do I need to do this weird stuff just to get a simple function type?
CodePudding user response:
Member pointers are not pointers. To strip one from a type, you need something like this:
template <typename> struct RemoveMemPtr {};
template <typename X, typename Y> struct RemoveMemPtr<X Y::*> {using type = X;};
However, this won't give you any new information. Given ReturnType (Class::*)(Params...)
, it will just return ReturnType(Params...)
, similar to how a regular function pointer type can be transformed to a function.
decltype(object::function)
doesn't work simply because the standard says so. When you name a member function, you must either call it immediately, or form a pointer to it.
Member functions formally do have a type, but there's no way to determine this type apart from forming a member pointer and stripping the pointer part from it. It's the same type as a free function with the same signature would have (implicit this
parameter is not included). Except that member functions can have const
/volatile
/&
/&&
qualifiers, and free functions can't.
As a piece of trivia, you can use those types to declare member functions:
using F = void(int) const;
struct A
{
F func; // void func(int) const;
};
CodePudding user response:
Your remove_pointer
is misnamed. It turns a type "pointer to a member of type T
of class object
" to T
, which is not directly related to the original type and is incompatible with entities of that type. The crucial piece of information about the original being a member of object
is lost. The template should better be named something like remove_membership
.
For example, it transforms the type of &object::function
, which is void (object::*)()
, to void()
. It isn't at all clear why you would want void()
while working with object::function
, as it is not compatible with void()
in any way.
Removing membership is a non-trivial, not generally useful transformation, so there is no built-in syntax to achieve it. If you need it, you just write a template that does it.