clamp
, min
, min_element
, max
, max_element
, minmax
, and minmax_element
. In this lesson, we introduce the minimum and maximum algorithms available within the C++ standard library.
All the algorithms in this section are available within the <algorithm>
 header:
#include <algorithm>
We will cover clamp
, min
, min_element
, max
, max_element
, minmax
, and minmax_element
.
Lets get started with clamp
std::ranges::clamp
The std::ranges::clamp
function is used to ensure a value is within a specific range.
The function takes three arguments, the value to clamp, the minimum allowed value. and the maximum allowed value
clamp
returns the minimumclamp
returns the maximumclamp
returns the valueThe following shows an example of clamping numbers to the 0-255Â range:
#include <algorithm>
#include <iostream>
int main() {
using std::ranges::clamp;
std::cout
<< "Clamp -30: " << clamp(-30, 0, 255)
<< "\nClamp 100: " << clamp(100, 0, 255)
<< "\nClamp 300: " << clamp(300, 0, 255);
}
Clamp -30: 0
Clamp 100: 100
Clamp 300: 255
The clamp
algorithm, and every other algorithm in this lesson, will return a const
reference to the chosen element:
#include <algorithm>
#include <iostream>
int main() {
int Value { 40 };
const int& ClampedValue {
std::ranges::clamp(Value, 0, 255)
};
Value = 50;
std::cout << ClampedValue;
}
50
std::ranges::min
The minimum value in a range can be retrieved using min
:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> Numbers { 2, 3, 1, 4, 5 };
const int& Result { std::ranges::min(Numbers) };
std::cout << "Smallest number: " << Result;
}
Smallest number: 1
If multiple objects are tied for the minimum, the algorithm will return the first (ie, leftmost) one in the range.
std::ranges::min_element
The min_element
function works in much the same way as min
. The key difference is that, whereas min
will return a reference to the smallest object, min_element
will return an iterator pointing to it.
In this example, we use this to insert a 0
before our minimum element:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> Numbers { 2, 3, 1, 4, 5 };
auto Result { std::ranges::min_element(Numbers) };
Numbers.emplace(Result, 0);
for (int& i : Numbers) {
std::cout << i << " ";
}
}
2 3 0 1 4 5
std::ranges::max
The maximum value in a range can be retrieved using the max
 algorithm:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector Numbers { 2, 3, 1, 4, 5 };
const int& Result { std::ranges::max(Numbers) };
std::cout << "Smallest number: " << Result;
}
Largest number: 5
If multiple objects are tied for the maximum, the algorithm will return the first (ie, leftmost) one in the range.
std::ranges::max_element
Similar to min
and min_element
, we can instead access an iterator that points to our maximum element. Here, we use the iterator to insert a 0
before our maximum element:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector Numbers { 2, 3, 1, 4, 5 };
auto Result { std::ranges::max_element(Numbers) };
Numbers.emplace(Result, 0);
for (int& i : Numbers) {
std::cout << i << " ";
}
}
2 3 1 4 0 5
std::ranges::minmax
We can retrieve both the minimum and maximum values in a range at once using the minmax
algorithm. This algorithm returns a struct with two properties: min
and max
. We can use it like this:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector Numbers { 2, 3, 1, 4, 5 };
const auto& Result { std::ranges::minmax(Numbers) };
std::cout << "Smallest: " << Result.min;
std::cout << "\nLargest: " << Result.max;
}
Smallest: 1
Largest: 5
Typically, we’d use structured binding when retrieving the results from minmax
:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector Numbers { 2, 3, 1, 4, 5 };
const auto& [min, max] {
std::ranges::minmax(Numbers)
};
std::cout << "Smallest number: " << min;
std::cout << "\nLargest number: " << max;
}
Smallest number: 1
Largest number: 5
If multiple objects are tied for the minimum, the min
property will contain the first (ie, the leftmost) one in the range
If multiple objects are tied for the maximum, the max
property will contain the last (ie, the rightmost) one in the range
std::ranges::minmax_element
Finally, we have minmax_element
, which will return iterators that point to the minimum and maximum objects of our range. Here, we use the iterators to insert a 0
before both our minimum and maximum elements:
#include <algorithm>
#include <iostream>
#include <list>
int main() {
std::list Numbers { 2, 3, 1, 4, 5 };
auto [min, max] {
std::ranges::minmax_element(Numbers)
};
Numbers.insert(min, 0);
Numbers.insert(max, 0);
for (int& i : Numbers) {
std::cout << i << " ";
}
}
2 3 0 1 4 0 5
For our custom types to be directly supported by minimum and maximum algorithms, they generally need to implement all six of the comparison operators: >
, <
, >=
, <=
, ==
, and !=
Here is an example:
#include <algorithm>
#include <iostream>
#include <vector>
struct MyStruct {
int Value;
bool operator<(const MyStruct& Other) const {
return Value < Other.Value;
}
bool operator<=(const MyStruct& Other) const {
return Value <= Other.Value;
}
bool operator>(const MyStruct& Other) const {
return Value > Other.Value;
}
bool operator>=(const MyStruct& Other) const {
return Value >= Other.Value;
}
bool operator==(const MyStruct& Other) const {
return Value == Other.Value;
}
bool operator!=(const MyStruct& Other) const {
return Value != Other.Value;
}
};
int main() {
std::vector Numbers {
MyStruct { 2 },
MyStruct { 3 },
MyStruct { 1 },
MyStruct { 4 },
MyStruct { 5 }
};
const MyStruct& min { std::ranges::min(Numbers) };
std::cout << "Smallest number: " << min.Value;
}
Smallest number: 1
An optional second argument to our min and max algorithms (aside from clamp
) allows us to specify a comparison function. This function will accept two objects of the appropriate type and should return true
if the first object is “smaller” than the second.
In this example, we use a custom comparison function to find out which character has the lowest health:
#include <algorithm>
#include <iostream>
#include <vector>
class Character {
public:
Character(std::string Name, int Health)
: Name(std::move(Name)), Health(Health){};
std::string GetName() const { return Name; }
int GetHealth() const { return Health; }
private:
std::string Name;
int Health;
};
int main() {
std::vector Party{
Character{"Legolas", 100},
Character{"Gandalf", 200},
Character{"Gimli", 500}
};
auto Comparer {
[](Character& A, Character& B) {
return A.GetHealth() < B.GetHealth();
}
};
const Character& LowestHealth {
std::ranges::min(Party, Comparer)
};
std::cout << "Lowest Health: "
<< LowestHealth.GetName();
}
Lowest Health: Legolas
All the algorithms in this lesson (aside from clamp
) accept an additional optional third argument, which can be a projection function. We cover projection in detail here:
In this example, we find the Character
with the lowest health, by passing a projection function to the min
 algorithm:
#include <algorithm>
#include <iostream>
#include <vector>
class Character {
public:
Character(std::string Name, int Health)
: Name(std::move(Name)), Health(Health){};
std::string GetName() const { return Name; }
int GetHealth() const { return Health; }
private:
std::string Name;
int Health;
};
int main() {
std::vector Party {
Character { "Legolas", 100 },
Character { "Gandalf", 200 },
Character { "Gimli", 500 }
};
const Character& LowestHealth {
std::ranges::min(Party, {}, &Character::GetHealth)
};
std::cout << "Lowest Health: "
<< LowestHealth.GetName();
}
Lowest Health: Legolas
Comprehensive course covering advanced concepts, and how to use them on large-scale projects.