Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a real world example for "smart pointer to member"?

To clarify a possible precedence ambiguity in the English language: We are taking about "smart (pointer to member)", not "(smart pointer) to member".

I would define a smart pointer to member as a class X with operator ->* (T* lhs, X rhs) overloaded.

In his article "Implementing operator->* for Smart Pointers", Scott Meyers only briefly touches smart pointer to member, because back then (1999) the specific problem was difficult enough for raw pointer to member (side note: the latter is solved elegantly with lambdas here).

Anyhow, Scott Meyers writes in a footnote:

Shortly after writing the draft of this article, one of my consulting clients showed me a problem that was naturally solved by smart pointers to members. I was surprised, too.

I've tried to find an example for such a natural smart pointer to member. But I could neither come up with anything myself nor did online search uncover what I was looking for.

Do you know of any real world "smart pointer to member" example?

EDIT: I'm not looking for any ->* overload (as done by some EDSLs). Aiming at examples with semantics that resemble the built-in ->*, my definition above explicitly requires lhs to be a raw pointer.

like image 645
Tobi Avatar asked Feb 07 '18 13:02

Tobi


1 Answers

You have a layout engine that should work with 90 degree rotation (height and width swapping).

Using smart member pointers you can make (foo->*x) and (foo->*y) swap meaning. The same smart x and y can work on different unrelated kinds of data (rectangles, points, vectors), even on types you don't own.

template<class F>
struct smart_pm_t {
  F f;
  template<class T>
  friend decltype(auto) operator->*(T* t, smart_pm_t const& self ) {
    return self.f(t);
  }
};

template<class F>
smart_pm_t<F> smart_pm( F f ) { return {std::move(f)}; }

auto x = smart_pm( [](auto* t)->decltype(auto) noexcept { return t->x; } );
auto y = smart_pm( [](auto* t)->decltype(auto) noexcept { return t->y; } );

and we can get fancier with them.

do_layout( data, x, y );

vs

do_layout( data, y, x );

solves the problem horizontally or vertically.

This is an actual (simplified) use case in actual production code that reduced code duplication and ironed out a whole pile of bugs, because we only had to fix the code once.

A right hand normal member pointer had the problem that we would have to pass an entire suite of member pointers, one per type that works on the left hand side.

In effect, we wrote a compile-time polymorphic member pointer.

like image 81
Yakk - Adam Nevraumont Avatar answered Oct 04 '22 20:10

Yakk - Adam Nevraumont