C++ Named Operators
Tags: cpp, todayilearned, tutorial, computerscience
Published: 2020-06-01 16:47:33

As I was revising C++ again because I am not using it daily but today what I have discovered is something that many people and even Fluent C++ Programmers don't know about. I am about to introduce `Named Operators`.

This post uses [klmr/named-operator](https://github.com/klmr/named-operator) library because it is convenient to explain and to look at. 

## Named Operators

Named Operators are those operators which are custom named and are surrounded by symbols like `+`, `-`, `*` etc. It is similar to how Haskell does it.

```cpp
std::vector<int> = {1, 2, 24};
bool result = 24 <in> vec;
```

## Definition

Operators can be defined for any function-like object by calling
`make_named_operator`:

```cpp
auto div = make_named_operator(div);
```

where

```cpp
int div(int x, int y) {
    return { x / y};
}
```

Or, if you prefer functors (and yes, templates work just fine):

```cpp
auto append = make_named_operator(append_t());
```

with

```cpp
struct append_t {
    template <typename T>
    vector<T> operator ()(vector<T> const& vs, T const& v) const {
        auto copy(vs);
        copy.push_back(v);
        return copy;
    }
};
```

And of course lambdas work as well:

```cpp
auto in = make_named_operator(
    [](int i, vector<int> const& x) {
        return find(begin(x), end(x), i) != end(x);
    });

bool result = 24 <in> vec;
```

## Design rationale & implementation

Overloading operators with unconventional semantics generally frowned upon because it violates the user’s expectations (although it has [variously](http://www.boost.org/doc/libs/1_53_0/libs/assign/doc/index.html) been used [to great effect](http://boost-spirit.com)).

Furthermore, the set of operators that can be created in this fashion is limited to a subset of the built-in operators.

On the other hand, using infix notation instead of function calls can undeniably make code more readable, especially when nesting lots of operations. Compare

```c++
auto result = contains(set_minus(set_minus(A, B), C), x);
```

and

```c++
auto result = x <in> (A <set_minus> B <set_minus> C);
```

Other languages have recognized and addressed this problem.

Since C++ allows overloading operators for custom types, named operators can be implemented by simply sticking a place-holder object between two overloaded operators (which can be entirely arbitrary):

```c++
struct some_tag {} op;
struct op_temporary {};
op_temporary operator <(int lhs, some_tag rhs);
int operator >(op_temporary lhs, int rhs);
```

These declarations are enough to make the following syntax valid:

```c++
int x, y, z;
z = x <op> y;
```

Of course, what the compiler really sees is

```c++
z = operator>(operator<(x, op), y);
```

This already highlights a problem: operator precedence. In effect, `op` will have the precedence of its surrounding operators. In particular, the precedence of `<` and `>` is very low

## GitHub Repo

{% github https://github.com/klmr/named-operator %}


## Note

This work and implementation is done by [klmr](https://github.com/klmr) so I don't take any credit of this work! I am just posting and sharing this knowledge!