Home > Net >  Getting the decltype of a member function?
Getting the decltype of a member function?

Time:05-29

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.

  • Related