27

This is a template function that takes a pointer (or a pointer like object) and a member function:

template <typename Ptr, typename MemberFunctor>
int example(Ptr ptr, MemberFunctor func )
{
    return (ptr->*func)();
}

If works when used with ordinary pointer:

struct C
{
    int getId() const { return 1; }
};

C* c = new C;
example(c, &C::getId);    // Works fine

But it does not work with smart pointers:

std::shared_ptr<C> c2(new C);
example(c2, &C::getId);

Error message:

error: C2296: '->*' : illegal, left operand has type 'std::shared_ptr<C>'

Why? and How to make something that works with both?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Meena Alfons
  • 1,230
  • 2
  • 13
  • 30

3 Answers3

29

std::shared_ptr doesn't support pointer-to-member access operator (i.e. ->* and .*). So we can't invoke member function pointers with ->* on it directly. You can change the invoking syntax to use operator* and operator.*, which works for both raw pointers and smart pointers.

template <typename Ptr, typename MemberFunctor>
int example(Ptr ptr, MemberFunctor func )
{
    return ((*ptr).*func)();
}

LIVE

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
12

std::shared_ptr doesn't have an operator->*. You have two main options:

You could write an overload which takes a std::shared_ptr (maybe one for std::unique_ptr as well):

template <typename T, typename MemberFunctor>
int example(std::shared_ptr<T> ptr, MemberFunctor func )
{
    return ((ptr.get())->*func)();
}

However, I would suggest just making example take a reference to T and calling func on it. example doesn't need to know anything about how the pointer is stored, so it shouldn't require all of these extra overloads.

template <typename T, typename MemberFunctor>
int example(T&& t, MemberFunctor func )
{
    return (std::forward<T>(t).*func)();
}

Now if you have a std::shared_ptr<T>, you'd call example like:

example(*my_shared_ptr, my_func); 
TartanLlama
  • 63,752
  • 13
  • 157
  • 193
7

std::shared_ptr doesn't overload operator ->*. You may add a overload:

template <typename Ptr, typename MemberFunctor>
int example(std::shared_ptr<Ptr> ptr, MemberFunctor func )
{
    return (ptr.get()->*func)();
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302