I have decided to write my own min
max
sum
functions. I really don't like the ones provided by the STL so I decided to write my own.
#include <type_traits>
namespace utils {
namespace detail {
template<typename T1, typename T2>
using BiggerT = typename std::conditional<sizeof(T1) >= sizeof(T2), T1, T2>;
template<typename T1, typename T2>
using FloatingPointOverBiggerT = typename std::conditional < std::is_floating_point<T1>::value || std::is_floating_point<T2>::value,
double, typename BiggerT<T1, T2>>;
template<typename...> struct BiggestType;
template<typename T1, typename T2, typename... RestT>
struct BiggestType<T1, T2, RestT...> {
using type = typename FloatingPointOverBiggerT<T1, typename BiggestType<T2, RestT...>::type>::type;
};
template<typename T>
struct BiggestType<T> {
using type = T;
};
template<typename T1, typename T2>
struct BiggestType<T1, T2>{
using type = typename FloatingPointOverBiggerT<T1, T2>::type;
};
template<typename FirstNumericT, typename SecondNumericT>
constexpr decltype(auto) Max(FirstNumericT&& first, SecondNumericT&& second) noexcept {
using Type = typename detail::BiggestType<FirstNumericT, SecondNumericT>::type;
return (static_cast<Type>(first) > static_cast<Type>(second)) ? static_cast<Type>(first) : static_cast<Type>(second);
}
template<typename FirstNumericT, typename SecondNumericT, typename... RestNumericT>
constexpr decltype(auto) Max(FirstNumericT&& first, SecondNumericT&& second, RestNumericT&&... restargs) noexcept {
using Type = typename detail::BiggestType<FirstNumericT, SecondNumericT, RestNumericT...>::type;
return Max((static_cast<Type>(first) > static_cast<Type>(second)) ?
static_cast<Type>(first) : static_cast<Type>(second), std::forward<RestNumericT&&>(restargs)...);
}
template<typename FirstNumericT, typename SecondNumericT>
constexpr decltype(auto) Min(FirstNumericT&& first, SecondNumericT&& second) noexcept {
using Type = typename detail::BiggestType<FirstNumericT, SecondNumericT>::type;
return (static_cast<Type>(first) < static_cast<Type>(second)) ? static_cast<Type>(first) : static_cast<Type>(second);
}
template<typename FirstNumericT, typename SecondNumericT, typename... RestNumericT>
constexpr decltype(auto) Min(FirstNumericT&& first, SecondNumericT&& second, RestNumericT&&... restargs) noexcept {
using Type = typename detail::BiggestType<FirstNumericT, SecondNumericT, RestNumericT...>::type;
return Min((static_cast<Type>(first) < static_cast<Type>(second)) ?
static_cast<Type>(first) : static_cast<Type>(second), std::forward<RestNumericT&&>(restargs)...);
}
template<typename LastNumericT>
constexpr decltype(auto) Sum(LastNumericT last) {
return last;
}
template<typename FirstNumericT, typename SecondNumericT, typename... RestNumericT>
constexpr decltype(auto) Sum(FirstNumericT&& first, SecondNumericT&& second, RestNumericT&&... restargs) noexcept {
using Type = typename detail::BiggestType<FirstNumericT, SecondNumericT, RestNumericT...>::type;
return Sum(static_cast<Type>(first) + static_cast<Type>(second), std::forward<RestNumericT&&>(restargs)...);
}
template < typename... >
using void_t = void;
template < typename T, typename Index >
using SubscriptT = decltype(std::declval<T>()[std::declval<Index>()]);
template < typename, typename Index = size_t, typename = void_t<> >
struct HasSubscriptOperator : std::false_type {};
template < typename T, typename Index >
struct HasSubscriptOperator< T, Index, void_t< SubscriptT<T, Index> > > : std::true_type {};
}
template<typename ReturnT = int, typename ContainerT, typename PredicateT, typename RawT =
typename std::remove_cv<typename std::remove_reference<ReturnT>::type>::type>
constexpr typename std::enable_if < utils::detail::HasSubscriptOperator<ContainerT>::value, RawT>::type
Max(const ContainerT& container, const PredicateT& predicate) {
auto result = predicate(*std::cbegin(container));
for(const auto& num : container) {
if(predicate(num) > result) {
result = predicate(num);
}
}
return result;
}
template<typename FirstT, typename SecondT, typename... NumericTypes>
constexpr typename std::enable_if < std::is_floating_point<FirstT>::value || std::is_integral<FirstT>::value,
typename utils::detail::BiggestType<FirstT, SecondT, NumericTypes...>::type>::type
Max(FirstT&& first, SecondT&& second, NumericTypes&&... args) noexcept {
return detail::Max(std::forward<FirstT&&>(first), std::forward<SecondT&&>(second), std::forward<NumericTypes&&>(args)...);
}
template<typename ContainerT>
constexpr decltype(auto) Max(const ContainerT& container) {
typename std::remove_cv<typename std::remove_reference<decltype(container[0])>::type>::type result = container[0];
for(const auto& num : container) {
if(num > result) {
result = num;
}
}
return result;
}
template<typename FirstT, typename SecondT, typename... NumericTypes>
constexpr typename std::enable_if < std::is_floating_point<FirstT>::value || std::is_integral<FirstT>::value,
typename utils::detail::BiggestType<FirstT, SecondT, NumericTypes...>::type>::type
Min(FirstT&& first, SecondT&& second, NumericTypes&&... args) noexcept {
return detail::Min(std::forward<FirstT&&>(first), std::forward<SecondT&&>(second), std::forward<NumericTypes&&>(args)...);
}
template<typename ReturnT = int, typename ContainerT, typename PredicateT, typename RawT =
typename std::remove_cv<typename std::remove_reference<ReturnT>::type>::type>
constexpr typename std::enable_if < utils::detail::HasSubscriptOperator<ContainerT>::value, RawT>::type
Min(const ContainerT& container, const PredicateT& predicate) {
auto result = predicate(*std::cbegin(container));
for(const auto& num : container) {
if(predicate(num) < result) {
result = predicate(num);
}
}
return result;
}
template<typename ContainerT>
constexpr decltype(auto) Min(const ContainerT& container) {
typename std::remove_cv<typename std::remove_reference<decltype(container[0])>::type>::type result = container[0];
for(const auto& num : container) {
if(num < result) {
result = num;
}
}
return result;
}
template<typename ReturnT = int, typename ContainerT, typename PredicateT, typename RawT =
typename std::remove_cv<typename std::remove_reference<ReturnT>::type>::type>
constexpr typename std::enable_if < utils::detail::HasSubscriptOperator<ContainerT>::value, RawT>::type
Sum(const ContainerT& container, PredicateT predicate) {
RawT result = 0;
for(const auto& num : container) {
result += predicate(num);
}
return result;
}
template<typename FirstT, typename SecondT, typename... NumericTypes>
constexpr typename std::enable_if < std::is_floating_point<FirstT>::value || std::is_integral<FirstT>::value,
typename utils::detail::BiggestType<FirstT, SecondT, NumericTypes...>::type>::type
Sum(FirstT&& first, SecondT&& second, NumericTypes&&... args) noexcept {
return detail::Sum(std::forward<FirstT&&>(first), std::forward<SecondT&&>(second), std::forward<NumericTypes&&>(args)...);
}
template<typename ContainerT>
constexpr decltype(auto) Sum(const ContainerT& container) {
typename std::remove_cv<typename std::remove_reference<decltype(container[0])>::type>::type result = 0;
for(const auto& num : container) {
result += num;
}
return result;
}
template<typename FirstT, typename SecondT, typename... NumericTypes>
constexpr decltype(auto) Avg(FirstT&& first, SecondT&& second, NumericTypes&&... args) noexcept {
return (detail::Sum(std::forward<FirstT&&>(first), std::forward<SecondT&&>(second), std::forward<NumericTypes&&>(args)...) / (2 + sizeof...(NumericTypes)));
}
Usage
std::vector<int> vecInt = {2, 3, 5, 2, 10};
std::map<int, std::size_t> mapInt = {{2, 2}, {3, 3}, {7, 7}};
int cInt[] = {2, 2, 2, 2};
auto vecSum = utils::Sum(vecInt);
auto mapSum = utils::Sum(mapInt, [](const auto& val) {return val.second;});
auto cSum = utils::Sum(cInt);
auto sum = utils::Sum(5, 7ULL, 5.5f, 70.0);
auto vecMax = utils::Max(vecInt);
auto mapMax = utils::Max(mapInt, [](const auto& val) {return val.second;});
auto cMax = utils::Max(cInt);
auto maxx = utils::Max(5, 55, 11, 33.0f, 55.0, 66ULL);
auto vecMin = utils::Min(vecInt);
auto mapMin = utils::Min(mapInt, [](const auto& val) {return val.second;});
auto cMin = utils::Min(cInt);
auto minn = utils::Min(5, 55, 11, 33.0f, 55.0, 66ULL);
auto avgg = utils::Avg(5, 55, 11, 33.0f, 55.0, 66ULL);
What do you think about the code?
#include <iterator>
and to remove thetypename
in front ofBiggerT
at line 8 (edit: you should rather add::type
after that). Your usage example should also#include <vector> /*and*/ <map>
and be expanded with some output to make behavior more explicit. \$\endgroup\$