Sometimes, we need to create wrapper types. For example, types like
unique_ptr
, shared_ptr
, optional
and similar.
Usually, these types have an accessor member function called
.get
but they also provide the operator->
to support direct access to the contained value similarly to what
ordinary pointers do.
The problem is that sometimes we have a few of these types nested
into each other. This means that we need to call .get
multiple times, or to have a lot of dereference operators until we reach
the value.
Something like this:
wrap<wrap<std::string>> wp;
wp.get().get().length();
wp.get()->length();
This can be a bit ugly. If we can replace one .get()
with an arrow, it would be nice if we could replace the second
.get()
as well. For this, the C++98 introduced a long arrow
operator.
wrap<wrap<std::string>> wp;
wp--->length();
What if we have another layer of wrapping? Just make a longer arrow.
wrap<wrap<wrap<std::string>>> wp;
wp----->length();
With a special implementation of wrap
, this compiles and
works without many problems.
Disclaimer
Now, before we continue, you should realize that this post is not a
serious one. And that this should never be used in a serious project,
just like the left arrow operator <--
[1]
and the WTF operator ??!??!
[2]
(which no longer works in C++17 BTW).
How?
Like in the <--
case, the long arrow is not a single
operator, but a combination of multiple operators. In this case, a
normal ->
operator and the postfix decrement operator
--
.
So, when we write wp----->length()
, the compiler sees
((wp--)--)->length()
.
If we define the postfix --
to be the same as the
dereference operator, we get the long arrow, and the even longer arrow
operators:
template <typename T>
class wrap {
public:
T* operator->() { return &t; }
T& operator--(int) { return t; }
private:
T t;
};