14

I've recently come across the need to apply a pointer-to-member to the object designated by an iterator. I've tried the natural syntax :

ite->*ptr = 42;

To my dismay, it didn't compile. Iterators don't overload operator->*, but more surprisingly neither do smart pointers. I needed to resort to the following clunkiness :

(*ite).*ptr = 42;

Experimenting (see the live example below) has shown that such a syntax seems to be achievable for custom classes, for both pointers-to-members and pointers-to-member-functions, at least since C++14.

Thus :

  • Is there a reason the standard pointer-like classes don't overload operator->*, or is it just an oversight ?
  • Should I overload operator->* when defining my own pointer-like classes, or does this same reason apply to me ?

Live example -- what compiles, what doesn't, and a proof-of-concept for a custom class.

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • 1
    @Galik I do mean pointers-to-members, not plain members. Have a look [here](http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_data_members). – Quentin Aug 06 '15 at 09:34
  • see http://stackoverflow.com/questions/14106975/error-in-using-unique-ptr-with-member-function-pointer some good points are made there – Hcorg Aug 06 '15 at 09:44
  • 1
    See also http://stackoverflow.com/questions/17696664/about-shared-ptr-and-pointer-to-member-operator-and-stdbind - although that's more about pointer to member functions rather than pointer to data members. – ecatmur Aug 06 '15 at 09:59
  • @Hcorg thank you very much, that was instructive -- member functions are indeed a pain. However they seem fine in C++14 (I updated the example). – Quentin Aug 06 '15 at 10:00
  • @ecatmur it did bring up something **really** interesting that I didn't realize : it's possible to define `operator->*` as a non-member. Unless such an operator is a terrible idea, it could be "hot-patched" onto the standard classes. Neat, thank you ! – Quentin Aug 06 '15 at 10:07
  • @Quentin so maybe standard committee did not though about it, when they made necessary changes in C++14 :) or they do not like pointer-to-members (AFAIK std::function and lambdas are preferred now) – Hcorg Aug 06 '15 at 10:09

2 Answers2

6

You can overload ->* with a free function. It doesn't have to be a member.

template <typename P,
          typename T,
          typename M>
M& operator->* (P smartptr, M T::*ptrmem)
{
    return (*smartptr).*ptrmem;
}

Now everything that has unary operator* defined (iterators, smart pointers, whatever) can also use ->*. You may want to do it in a bit more controlled fashion, i.e. define it for known iterators, known smart pointers etc. separately.

This will not work for member functions for obvious reasons. One would need to specialize/overload for this case and return a bound std::function instead:

template <typename P,
          typename T,
          typename M,
          typename ... Arg>
std::function<M(Arg&&...)> 
operator->* (P smartptr, M (T::*ptrmem)(Arg... args))
{
    return [smartptr,ptrmem](Arg&&... args) -> M 
      { return ((*smartptr).*ptrmem)(std::forward<Arg>(args)...); };
}
Quentin
  • 62,093
  • 7
  • 131
  • 191
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
0

Is that what you want to do ((&*ite)->*ptr) = 42; ?

Axel Payan
  • 99
  • 7
  • Sorry. Is that it `((&*ite)->*ptr) = 42;` ? – Axel Payan Aug 06 '15 at 10:10
  • This works, but is specifically the work-around I'd like not to have to use. Do notice that the question is not about a practical problem to be solved, but why it couldn't be solved with natural syntax, even though it is technically possible to achieve that syntax. – Quentin Aug 06 '15 at 10:13
  • In fact there is a natural syntax `ite->*ptr = 42;` that's calling the member of the iterator class. If you overload the operator, you can't use it to call members of the iterator. That's why it isn't. – Axel Payan Aug 06 '15 at 11:07
  • But an iterator is not a pointer, so without overloading `ite->*ptr` is incorrect, `ite.*ptr` is. Anyway, multiple overloads can distinguish between members belonging to the iterator, and members belonging to its pointee. – Quentin Aug 06 '15 at 11:51
  • Also, I didn't notice that you don't have the required reputation to comment yet, sorry about that. – Quentin Aug 06 '15 at 11:51