-
-
Save gyakoo/96e6aeb9039b81c74b7a438db2c0aa37 to your computer and use it in GitHub Desktop.
C++11 variadic max, min, and minmax implementations.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <utility> | |
// varidic max, min, and minmax implementation (named maximum, minimum and min_max to avoid confusion) | |
// no support for custom comparators (mainly because i'm not sure how they should be specified) | |
namespace detail { | |
// max base case | |
template <class T> | |
constexpr T const &do_max(T const &v) { | |
return v; | |
} | |
// max inductive case | |
template <class T, class... Rest> // requires SameType<T, Rest...> | |
constexpr T const &do_max(T const &v0, T const &v1, Rest const &... rest) { | |
return do_max(v0 < v1 ? v1 : v0, rest...); | |
} | |
// min base case | |
template <class T> | |
constexpr T const &do_min(T const &v) { | |
return v; | |
} | |
// min variadic inductive case | |
template <class T, class... Rest> // requires SameType<T, Rest...> | |
constexpr T const &do_min(T const &v0, T const &v1, Rest const &...rest) { | |
return do_min(v0 < v1 ? v0 : v1, rest...); | |
} | |
// min_max base case | |
template <class T> | |
constexpr std::pair<T const&, T const&> | |
do_min_max(T const &cmin, T const &cmax) { | |
return { cmin, cmax }; | |
} | |
// min_max inductive case | |
template <class T, class... Rest> // requires SameType<T, Rest...> | |
constexpr std::pair<T const &, T const &> | |
do_min_max(T const &cmin, T const &cmax, T const &next, Rest const &... rest) { | |
return do_min_max( | |
cmin < next ? cmin : next, | |
next < cmax ? cmax : next, | |
rest... | |
); | |
} | |
} // namespace detail | |
// public interface for minimum | |
template <class T, class ...Rest> // requires SameType<T, Rest...> | |
inline constexpr T const & | |
minimum(T const &first, Rest const &... rest) { | |
return detail::do_min(first, rest...); | |
} | |
// public interface for maximum | |
template <class T, class ...Rest> // requires SameType<T, Rest...> | |
inline constexpr T const & | |
maximum(T const &first, Rest const &... rest) { | |
return detail::do_max(first, rest...); | |
} | |
// public interface for min_max | |
template <class T, class ...Rest> // requires SameType<T, Rest...> | |
inline constexpr std::pair<T const &, T const &> | |
min_max(T const &first, Rest const &... rest) { | |
return detail::do_min_max(first, first, rest...); | |
} | |
// tests | |
namespace test_detail { | |
#define MIN_MAX_STATIC_TEST_CASE(FIRST, SECOND, ...) \ | |
static_assert(min_max(__VA_ARGS__).first == FIRST, "bad min_max.first"); \ | |
static_assert(min_max(__VA_ARGS__).second == SECOND, "bad min_max.second"); \ | |
static_assert(minimum(__VA_ARGS__) == FIRST, "bad minimum"); \ | |
static_assert(maximum(__VA_ARGS__) == SECOND, "bad maximum") | |
template <class T> | |
struct MinMaxTester { | |
MIN_MAX_STATIC_TEST_CASE(T{+1}, T{5}, T{1}, T{2}, T{3}, T{4}, T{5}); | |
MIN_MAX_STATIC_TEST_CASE(T{+1}, T{5}, T{5}, T{4}, T{3}, T{2}, T{1}); | |
MIN_MAX_STATIC_TEST_CASE(T{-1}, T{5}, T{5}, T{1}, T{5}, T{1}, T{2}, T{0}, T{-1}, T{1}, T{2}, T{2}); | |
MIN_MAX_STATIC_TEST_CASE(T{20}, T{20}, T{20}); | |
}; | |
#undef MIN_MAX_STATIC_TEST_CASE | |
// type offering operator< but not operator> | |
struct NoGreater { | |
int v; | |
constexpr NoGreater(int n) : v(n) {} | |
constexpr bool operator<(NoGreater const &o) const { return v < o.v; } | |
constexpr bool operator==(NoGreater const &o) const { return v == o.v; } // for use with MIN_MAX_STATIC_TEST_CASE | |
}; | |
typedef MinMaxTester<int> MinMaxTestInt; | |
typedef MinMaxTester<float> MinMaxTestFloat; | |
typedef MinMaxTester<NoGreater> MinMaxTestNoGreater; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment