I have written the following generic function template:
#include <iostream>
#include <array>
#include <span>
#include <iterator>
#include <concepts>
#include <compare>
#include <cstddef>
template <typename T>
requires ( std::totally_ordered<T> && std::three_way_comparable<T> )
[[ nodiscard ]] constexpr std::ptrdiff_t
binarySearch( const std::span<const T> spn, const T target) noexcept
{
std::ptrdiff_t result;
std::ptrdiff_t lowerBound { };
std::ptrdiff_t upperBound { std::distance( std::cbegin( spn ), std::cend( spn ) ) - 1 };
while ( lowerBound <= upperBound )
{
std::ptrdiff_t mid { lowerBound + ( upperBound - lowerBound ) / 2 };
if ( spn[ mid ] == target )
{
return result = mid;
}
else if ( spn[ mid ] < target )
{
lowerBound = mid + 1;
}
else
{
upperBound = mid - 1;
}
}
return result = -1;
}
int main( )
{
const std::array<long long, 5> arr { 3, 44, 44, 1000, 1050 };
const auto lowerBound { std::cbegin( arr ) };
const auto upperBound { std::cend( arr ) };
const long long target { 44 };
std::ptrdiff_t resultIndex { binarySearch( { lowerBound, upperBound } , target ) };
if ( resultIndex == -1 )
{
std::cout << "The element <<" << target
<< ">> is not present in the span\n";
}
else
{
std::cout << "The element <<" << target << ">> is present at index "
<< resultIndex << " of the span\n";
}
}
- Is the above function safe and robust? I want to discover the potential flaws that it has.
- What parts of it could be improved? For instance what other concepts should I add to the
requiresclause?
Also, I want to mention that I aim to make sure that T is a type that when compared using comparison operators, results in either a std::strong_ordering or a std::weak_ordering so that the binary search algorithm works properly. Is this a good idea? And if so then how should I ensure that it happens?
std::uint64_t. However I chose something else for this example. \$\endgroup\$