Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the class of a member function pointer?

Tags:

c++

c++11

Consider the code:

class Character
{
  void kill();
  void send_to_wall();
}

template <typename T>
void GeorgeFunc(T fp)
{
  ??? obj;
  (obj.*fp)();
}

int main()
{
  GeorgeFunc(&Character::kill);
}

So my question here is: how can I get ???? It seems that the compiler definitely knows what this type is (Character) during template instantiation, but I'm not sure how to get at it. My current workaround is to change to: void GeorgeFunc(void (T::*fp)()), but it would be cleaner to simply get the type from the member function pointer. decltype(fp) would return void(Character::*)(), and decltype(fp()) would return void. Any way to get Character?

like image 812
Rollie Avatar asked Jan 23 '15 07:01

Rollie


People also ask

How do you access pointer data members of a class?

A pointer to a C++ class is done exactly the same way as a pointer to a structure and to access members of a pointer to a class you use the member access operator -> operator, just as you do with pointers to structures. Also as with all pointers, you must initialize the pointer before using it.

What is the syntax of pointer to member function?

A pointer to a member can be declared and used as shown in the following code fragment: typedef int X::*my_pointer_to_member; typedef void (X::*my_pointer_to_function) (int); int main() { my_pointer_to_member ptiptr = &X::a; my_pointer_to_function ptfptr = &X::f; X xobject; xobject.*ptiptr = 10; cout << "The value of a ...

Which is the pointer to a member of a class operator?

There are two pointer to member operators: . * and ->* . The . * operator is used to dereference pointers to class members.

Is it possible to create a pointer to member function of any class?

In C++ , function pointers when dealing with member functions of classes or structs, it is invoked using an object pointer or a this call. We can only call members of that class (or derivatives) using a pointer of that type as they are type safe.


1 Answers

Yes, just use a trait to determine this.

template <typename> struct member_function_traits;

template <typename Return, typename Object, typename... Args>
struct member_function_traits<Return (Object::*)(Args...)>
{
    typedef Return return_type;
    typedef Object instance_type;
    typedef Object & instance_reference;

    // Can mess with Args... if you need to, for example:
    static constexpr size_t argument_count = sizeof...(Args);
};

// If you intend to support const member functions you need another specialization.
template <typename Return, typename Object, typename... Args>
struct member_function_traits<Return (Object::*)(Args...) const>
{
    typedef Return return_type;
    typedef Object instance_type;
    typedef Object const & instance_reference;

    // Can mess with Args... if you need to, for example:
    static constexpr size_t argument_count = sizeof...(Args);
};

Now your declaration is:

typename member_function_traits<T>::instance_type obj;

However, I would argue that since you require a member function pointer (other types would fail to instantiate due to the line (obj.*fp)()1) that your function should take a member function pointer directly instead of a completely generic type.

So this definition would not only work, but I would consider it preferred -- the error messages when someone uses something other than a pointer-to-member-function will be much clearer because the argument type will be incompatible:

template <typename Return, typename Object>
void GeorgeFunc(Return (Object::*fp)())
{
    Object obj;
    (obj.*fp)();
}

Note that this does allow passing a pointer-to-member-function that returns any type. Since we don't really use the return value, we don't care what it is. There is no reason to enforce that it is void as in your "workaround."

The only downside to using this approach is that you need two overloads if you intend to also accept pointers to member functions that are declared const. The completely generic implementation does not have this limitation. (I've long wished that pointers to const member functions were implicitly convertible to pointers to non-const member functions, but this is currently not allowed by C++.)


1 This isn't 100% true. If you use a completely generic type as you are right now then the caller could theoretically pass a member data pointer instead of a member function pointer. obj.*fp would evaluate as a reference to the data member, and then you would be invoking operator()() on it. As long as the data member's type implemented this operator then the template function GeorgeFunc could be instantiated.

like image 113
cdhowie Avatar answered Oct 14 '22 17:10

cdhowie