'What a struct/class has to implement to work with many (if not all) STL features when it's inside a container?

For example, if I have a struct to hold some information like this:


struct Two {
  int a, b;
}

I don't want to use a tuple and I can't use C++20 and <=> (the highest I can go is C++17).

Then what is the minimum set of operand overloads (and other functions) I have to implement to make it work with all (or most of the) STL algorithms and containers?

If I will assume the user will not do any operation on his own, like these:

Two a(1,2);
Two b(2,3);
const float c = 1.4;

a *= b;
a *= 2;
a += c;

And I do not want to provide anything extra implementation for the user's convenience, only to support the STL.

Is there a documentation page similar to https://www.cplusplus.com/reference/stl/ summarizing them in one document and what they need to have implemented to function?



Solution 1:[1]

Note: Yes for this example using a Tuple<int, int> would be more suiting

I disagree. Tuple lacks the ability to give a name for the type and for the members. That is a significant drawback in most cases.

Let's give it default and initializing constructors:

  Two(void): a(0), b(0) {
  }

  Two(int x, int y): a(x), b(y) {
  }

I recommend against this in most cases. Aggregate classes are useful.

have to implement my hashFunction. If I understand it correctly that applies to set, map and unordered_map.

No, you don't need a hash function for set nor map. You only need a hash function for unordered containers. For set and map, the keys must be orderable instead.

If I then use this unordered_set, but want to order it:

std::unordered_set<Two, hashFunction> exist;
std::sort(exist.begin(), exist.end());

This isn't possible. You cannot sort unordered containers (the clue is in the name). The iterators of the set are const.

Then I have to implement the - operator so it can compare the diff to know if it's bigger/smaller.

Subtraction operator isn't necessary to sort objects. What you need is a way to compare them. This can be done with a less-than operator, but it isn't necessary since you may use a comparison functor instead (just like you used a hash functor in your example).

If I want to use .find on this set:

auto it = exist.find(Two(i, index)

Then I have to implement the == operator:

Equality comparison is a general requirement of the unordered containers whether you want to use find or not. The equality operator isn't required if you use an equality comparator functor instead.

then how I could know what to implement in the advance?

You don't need to know, because the standard containers and algorithms support custom functors for all such functionality. The user of the class can implement those in any way they prefer.

But you can implement all the operators expected from regular types for convenience of the user of the class. I recommend adding all relational operators like this (C++20 required):

struct Two {
    int a, b;
    friend auto operator<=>(const Two&, const Two&) = default;
};

In general, you can know what standard library containers and algorithms require by reading their documentation.

if we are using at max C++17 ?

Then you must implement each comparison operator explicitly. Only less-than and equality are used by standard library containers, but it's convenient to have all. You can reduce boilerplate by using a base class such as those from Boost.Operators library.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1