I'm currently reading Mastering Perl for Bioinformatics; I'm using the book for learning bioinformatics while implementing the code in C++. I came across a situation where I needed to use the minimum of three numbers, which the author did using a function call min3
which, as expected, returns the minimum of three numbers.
Rather than using the canonical C-style macro #define MIN(a,b) ...
, I wanted to try and write more idiomatic C++, first by staying away from macros, and second by using templates to write type-safe, variadic Min
and Max
functions.
namespace Math
{
template <typename T1, typename T2>
constexpr inline auto Max(T1 a, T2 b) noexcept
{
return (a > b) ? a : b;
}
template <typename T1, typename T2, typename... Types>
constexpr inline auto Max(T1 a, T2 b, Types... args) noexcept
{
return Max(a, Max(b, args...));
}
template <typename T1, typename T2>
constexpr inline auto Min(T1 a, T2 b) noexcept
{
return (a < b) ? a : b;
}
template <typename T1, typename T2, typename... Types>
constexpr inline auto Min(T1 a, T2 b, Types... args) noexcept
{
return Min(a, Min(b, args...));
}
} // namespace Math
Example usage:
std::cout << Math::Max(1,2) << std::cout.widen('\n');
std::cout << Math::Min(3,8,4,3,2) << std::cout.widen('\n');
Output:
2
2
I'm using std::cout.widen('\n')
so as to not call std::fflush()
on each call to std::endl
.
1 Answer 1
Your implementation will work nicely for integers, however, it might be doing a lot of copies which could hurt you for more expensive types.
An edge case that might sometimes be useful in case of calling this via a template: the min/max of 1 number.
Your noexcept is wrong in case of throwing copy constructors. You could change this to noexcept(std::is_nothrow_copy_constructable<T>)
or fix the remark above and prevent copies.
Looking at the template arguments, you do allow T1 and T2 to be of a different type. I don't see much added value in that, as you would get an obscure error about the ?:
operator.
And to end with a positive note: I really like the constexpr. This allows you to write a unit test as a static_assert.
-
\$\begingroup\$ I thought allowing for different types might be handy in case you had to compare a long and a double, or something, but I do agree it doesn't seem great in retrospect. I really appreciate the feedback, this gave me a lot to think about \$\endgroup\$Jose Fernando Lopez Fernandez– Jose Fernando Lopez Fernandez2019年03月22日 11:30:33 +00:00Commented Mar 22, 2019 at 11:30
min(a, b)
should returna
ifa == b
; it currently returnsb
. \$\endgroup\$