Baduit

A young French developper who really likes (modern) C++

About me
08 April 2023

Play with the long arrow --> and overload it

by Baduit

Article::Article

Have you ever heard of the person who thought they found a new operator -->. If you haven’t, look at this Stack Overflow thread and read the responses (except the validated and boring one), it is pretty hilarious.

Anyway, wouldn’t it be cool if we could create new operators like they can do in Swift. A part of me want to learn Swift just for this feature, even if I am not a mobile dev and that I don’t even have a Mac or an iPhone.

But in C++ we can’t… or can we? Well, we can’t create operators from scratch, but we can combine existing operators.

DBZ fusion between operator -- and operator > to create a new super operator -->

In this article, we’ll see how to make funny thing with a long arrow -->.

The idea

When we write: x-->0, it is just the combination of the post decrement operator and then a comparison operator and both are overloadable.

meme template: Anthony Adams Rubbing Hands. Me when I see that an operator is overloadable

It means that that if we overload the operator --, returns something, and that something we return have the operator > overloaded, even if we technically are not overloading an operator --> it feels a bit like it.

Example

If you want to have a counter, and you want to target a specific value, you could do this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>

struct Counter
{
	auto operator --(int)
	{
        struct Tmp
        {
            auto operator>(int destination)
            {
                if (c.i == destination)
                {
                    return false;
                }
                else
                {
                    c.i += (c.i > destination) ? -1 : 1;
                    return true;
                }
            }

            Counter& c;
        };

        return Tmp{*this};
		
	}

	int i;
};

int main(int, char **)
{
	Counter c{10};
	while (c-->15)
	{
		std::cout << c.i << std::endl;
	}
}

Compiler explorer link

Mess with your colleagues

If you want to mess with your colleagues or make a good April fool’s joke, just send them this code with this link on Compiler Explorer and make them believe that the operator --> was added to the standard and that it is named to (in the same way that the operator && is called and and that you can write and instead of &&):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// This code is almost the same as the snippet above, 
#include <type_traits>
#include <concepts>
#include <iostream>

struct Counter
{
	auto operator to(int destination)
	{
		if (i == destination)
		{
			return false;
		}
		else
		{
			i += (i > destination) ? -1 : 1;
			return true;
		}
	}

	int i;
};

int main(int, char **)
{
	Counter c{10};
	while (c-->15)
	{
		std::cout << c.i << std::endl;
	}
}

I promise you it will be fun, I have done it and even if almost no one felt into the trap, they still scratched their head to understand how I made this snippet.

Implement the unified call syntax with it

If you haven’t read my article about unified call syntax, I advise you to read it to understand this section.

To summarize the previous article, I used the operator ->* to be able to do that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <vector>
#include <algorithm>

#include <unic/unic.hpp>

int main()
{
	using unic::operator->*;
	constexpr auto find = UNIC_GENERATE_PROXY(std::ranges::find);
	std::vector ints = { 1, 2, 3, 4, 5 };

	auto it = ints->*find(3);
	if (it != ints.cend())
		std::cout << "Found : " << *it << std::endl;
	else
		std::cout << "Not found :'(" << std::endl;
}

And wrote a little library about it.

I did almost the same for the long arrow --> and wrote another little library named long_arrow (Yes, I know, I was not very inspired for the name). With it you can do that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <long_arrow/long_arrow.hpp>

LONG_ARROW_GENERATE_OPERATOR_POST_DECREMENT(std::string)

constexpr std::string concat_const(const std::string& str, char c)
{
	return str + c;
}

constexpr void concat_mut(std::string& str, char c)
{
	str += c;
}

constexpr std::string concat_rvalue(std::string&& str, char c)
{
	return std::move(str += c);
}

int main()
{
	using long_arrow::operator>;

	{
		auto concat = LONG_ARROW_GENERATE_PROXY(concat_const);
		std::string str = "Hell";
		std::string res = str-->concat('o');
		std::cout << res << std::endl; // Hello
	}
	{
		auto concat = LONG_ARROW_GENERATE_PROXY(concat_mut);
		std::string str = "Hell";
		str-->concat('o');
		std::cout << str << std::endl;
	}
	{
		auto concat = LONG_ARROW_GENERATE_PROXY(concat_rvalue);
		std::string str = std::string("Hell")-->concat('o');
		std::cout << str << std::endl;
	}
}

I won’t go into the detail because I could write a little article about it, I just wanted to show an example of what it is possible to do with the long arrow.

Article::~Article

I hope you had as much fun reading this article as I got writing it!
It is another article where I showed you that you can do funny stuff and play with the C++ syntax. Also, that’s not because something is possible that you should do it, I don’t see the “operator -->” useful except maybe if you are creating a DSL (domain specific language) in C++.

Oh and don’t forget to tell me if you have found how I made the snippet to mess with the colleagues works! I’m really proud of how hard it is to see it haha.

Sources

tags: cpp