Max function with variable number of arguments
I think this function is unnecessary.

We can deal with defective classes (that don't properly implement the standard LessThanComparable concept) by either fixing them (preferable) or by providing a comparator argument to std::max:

auto const b_lessthan = [](const B&amp; a, const B&amp; b){ return !(a&gt;=b); };

std::max({B{}, B{}, B{}, B{}, B{}}, b_lessthan);


Sure, you could make a generic adapter using the same if constexpr chain as in this code, but are the defective types really that common?



We can arrange for std::max() to return an lvalue by passing it an initialiser list of std::reference_wrapper for its arguments:

template&lt;typename... T&gt;
constexpr auto&amp; ref_max(T... args)
{
    return std::max({std::ref(args)...,}).get();
}




We now have

#include &lt;algorithm&gt;
#include &lt;functional&gt;
#include &lt;cassert&gt;

int main()
{
    static_assert(std::max(1, 2) == 2);

    int a = 1;
    int b = 5;
    int c = 3;
    int d = 2;

    assert(std::max({a, b, c, d}) == b);

    ref_max(b, c, d) = 4;

    assert(b == 4);

    // This gives a compilation error because the static assertion failed
    // (void)std1::max(A{}, A{});

    // This works
    auto const b_lessthan = [](const B&amp; a, const B&amp; b){ return !(a&gt;=b); };

    std::max({B{}, B{}, B{}, B{}, B{}}, b_lessthan);
}


Which isn't so very different than the main() in the question.