Replacing MIN and MAX macros with type-safe, recursive templates of variable arity 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 &lt;typename T1, typename T2&gt;
    constexpr inline auto Max(T1 a, T2 b) noexcept
    {
        return (a &gt; b) ? a : b;
    }

    template &lt;typename T1, typename T2, typename... Types&gt;
    constexpr inline auto Max(T1 a, T2 b, Types... args) noexcept 
    {
        return Max(a, Max(b, args...));
    }

    template &lt;typename T1, typename T2&gt;
    constexpr inline auto Min(T1 a, T2 b) noexcept
    {
        return (a &lt; b) ? a : b;
    }

    template &lt;typename T1, typename T2, typename... Types&gt;
    constexpr inline auto Min(T1 a, T2 b, Types... args) noexcept
    {
        return Min(a, Min(b, args...));
    }
} // namespace Math


Example usage:

std::cout &lt;&lt; Math::Max(1,2)       &lt;&lt; std::cout.widen('\n');
std::cout &lt;&lt; Math::Min(3,8,4,3,2) &lt;&lt; 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.
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&lt;T&gt;) 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.