Q: Given a function constexpr int Min(int a, int b)
, construct a function constexpr int Min(Args... args)
that returns the minimum of all the provided args. Fail to justify your over-engineering.
A: Rename Min(int, int)
as MinImpl(int, int)
or stick it in a namespace. Overloading the function is not only unnecessary, it gets in the way of the implementation.
constexpr int MinImpl(int a, int b) { return a < b ? a : b; }
Implement a constexpr
fold left function. If we can use it for Min()
, we should be able to do the same for Max()
, and other similar functions. Should we be able to find any (#prematuregeneralization).
template<typename ArgA, typename ArgB, typename Func> constexpr auto foldl(Func func, ArgA a, ArgB b) { return func(a, b); } template<typename ArgA, typename ArgB, typename Func, typename ...Args> constexpr auto foldl(Func func, ArgA a, ArgB b, Args... args) { return foldl(func, func(a, b), args...); }
Combine the two.
template<typename ...Args> constexpr auto Min(Args... args) { return foldl(MinImpl, args...); }
Add the bare minimum amount of testing for a constexpr function: slap a static_assert()
on it.
static_assert(Min(6, 4, 5, 3, 9) == 3), "Nope");
I did so with Visual Studio 2015 Update 2. It did not object.
Addendum: Some discussion with @nlguillemot and @DrPizza led to this attempt to do something similar with a C++17/C++1z fold-expression:
#include <limits.h> constexpr int MinImpl1(int a, int b) { return a < b ? a : b; } constexpr void MinImpl2(int* m, int a, int b) { *m = a < b ? a : b; } template<typename ...Args> constexpr int Min(Args... args) { int m = INT_MAX; // a binary expression in an operand of a fold-expression // is not allowed, so this won't compile: //((m = MinImpl1(m, args), ...); // But this does: (MinImpl2(/*out*/&m, m, args), ...); return m; } int main() { static_assert(Min(3,4,5) == 3, "nope"); }
This compiles with a gcc-6 pre-release snapshot.
Update: Here’s a further updated version, based on a refinement by @dotstdy.