Skip to content

Commit 7e1f955

Browse files
author
ecrypa
committed
implement min_element (guarded for SFINAE)
1 parent ebda810 commit 7e1f955

File tree

3 files changed

+235
-0
lines changed

3 files changed

+235
-0
lines changed

example/src/list.cpp

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,4 +677,187 @@ IS_SAME(
677677
);
678678
/// [accumulate]
679679
)
680+
681+
HIDE(
682+
/// [min_element]
683+
using nums = metal::numbers<4, 42, 17, -7, 0>;
684+
685+
using comp_lt = metal::lambda<metal::less>;
686+
IS_SAME(metal::min_element<nums, comp_lt>, metal::number<-7>);
687+
688+
using comp_gt = metal::lambda<metal::greater>;
689+
IS_SAME(metal::min_element<nums, comp_gt>, metal::number<42>);
690+
691+
using vals = metal::list<const char[3], char[1], char[1], char[3], const char[1]>;
692+
693+
template<typename x, typename y>
694+
using smaller = metal::number<(sizeof(x) < sizeof(y))>;
695+
IS_SAME(metal::min_element<vals, metal::lambda<smaller>>, char[1]);
696+
697+
template<typename x, typename y>
698+
using larger = metal::number<(sizeof(x) > sizeof(y))>;
699+
IS_SAME(metal::min_element<vals, metal::lambda<larger>>, const char[3]);
700+
/// [min_element]
701+
)
702+
703+
HIDE(
704+
template<template<class...> class tmpl, class... args>
705+
using is_sfinae_friendly = metal::is_invocable<metal::lambda<tmpl>, args...>;
706+
707+
using some_extra_argument = int;
708+
709+
using attempt_to_instantiate = is_sfinae_friendly<
710+
metal::detail::_min_element<metal::lambda<std::is_void>>::template combiner,
711+
void, some_extra_argument, char
712+
>;
713+
)
714+
715+
HIDE(
716+
template<class, class>
717+
using good_comp = metal::false_;
718+
719+
static_assert(
720+
metal::is_invocable<
721+
metal::lambda<metal::min_element>,
722+
metal::numbers<4, 42, 17, -7, 0>,
723+
metal::lambda<good_comp>
724+
>{}, "");
725+
)
726+
727+
HIDE(
728+
template<class...>
729+
using good_comp = metal::false_;
730+
731+
static_assert(
732+
metal::is_invocable<
733+
metal::lambda<metal::min_element>,
734+
metal::numbers<4, 42, 17, -7, 0>,
735+
metal::lambda<good_comp>
736+
>{}, "");
737+
)
738+
739+
HIDE(
740+
template<class, class...>
741+
using good_comp = metal::false_;
742+
743+
static_assert(
744+
metal::is_invocable<
745+
metal::lambda<metal::min_element>,
746+
metal::numbers<4, 42, 17, -7, 0>,
747+
metal::lambda<good_comp>
748+
>{}, "");
749+
)
750+
751+
HIDE(
752+
template<class, class>
753+
struct good_lazy_comp {
754+
using type = metal::false_;
755+
};
756+
757+
template<class... args>
758+
using good_comp = typename good_lazy_comp<args...>::type;
759+
760+
static_assert(
761+
metal::is_invocable<
762+
metal::lambda<metal::min_element>,
763+
metal::numbers<4, 42, 17, -7, 0>,
764+
metal::lambda<good_comp>
765+
>{}, "");
766+
)
767+
768+
HIDE(
769+
template<class, class, class...>
770+
struct good_lazy_comp {
771+
template<class...>
772+
using type = metal::false_;
773+
};
774+
775+
template<class... args>
776+
using good_comp = typename good_lazy_comp<args...>::template type<args...>;
777+
778+
static_assert(
779+
metal::is_invocable<
780+
metal::lambda<metal::min_element>,
781+
metal::numbers<4, 42, 17, -7, 0>,
782+
metal::lambda<good_comp>
783+
>{}, "");
784+
)
785+
786+
HIDE(
787+
template<class>
788+
struct bad_lazy_comp {
789+
using type = metal::false_;
790+
};
791+
792+
template<class... args>
793+
using bad_comp = typename bad_lazy_comp<args...>::type;
794+
795+
static_assert(
796+
!metal::is_invocable<
797+
metal::lambda<metal::min_element>,
798+
metal::numbers<4, 42, 17, -7, 0>,
799+
metal::lambda<bad_comp>
800+
>{}, "");
801+
)
802+
803+
HIDE(
804+
template<class>
805+
using bad_comp = metal::false_;
806+
807+
static_assert(
808+
!metal::is_invocable<
809+
metal::lambda<metal::min_element>,
810+
metal::numbers<4, 42, 17, -7, 0>,
811+
metal::lambda<bad_comp>
812+
>{}, "");
813+
)
814+
815+
HIDE(
816+
template<class, class, class>
817+
using bad_comp = metal::false_;
818+
819+
static_assert(
820+
!metal::is_invocable<
821+
metal::lambda<metal::min_element>,
822+
metal::numbers<4, 42, 17, -7, 0>,
823+
metal::lambda<bad_comp>
824+
>{}, "");
825+
)
826+
827+
HIDE(
828+
template<class, class, class, class...>
829+
using bad_comp = metal::false_;
830+
831+
static_assert(
832+
!metal::is_invocable<
833+
metal::lambda<metal::min_element>,
834+
metal::numbers<4, 42, 17, -7, 0>,
835+
metal::lambda<bad_comp>
836+
>{}, "");
837+
)
838+
839+
HIDE(
840+
template<class, class>
841+
struct bad_comp;
842+
843+
static_assert(
844+
!metal::is_invocable<
845+
metal::lambda<metal::min_element>,
846+
metal::numbers<4, 42, 17, -7, 0>,
847+
metal::lambda<bad_comp>
848+
>{}, "");
849+
)
850+
851+
HIDE(
852+
template<class, class>
853+
struct bad_comp {};
854+
855+
static_assert(
856+
!metal::is_invocable<
857+
metal::lambda<metal::min_element>,
858+
metal::numbers<4, 42, 17, -7, 0>,
859+
metal::lambda<bad_comp>
860+
>{}, "");
861+
)
862+
680863
#endif

include/metal/list.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "list/iota.hpp"
2929
#include "list/join.hpp"
3030
#include "list/list.hpp"
31+
#include "list/min_element.hpp"
3132
#include "list/none_of.hpp"
3233
#include "list/partition.hpp"
3334
#include "list/powerset.hpp"

include/metal/list/min_element.hpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#ifndef METAL_LIST_MIN_ELEMENT_HPP
2+
#define METAL_LIST_MIN_ELEMENT_HPP
3+
4+
#include "../config.hpp"
5+
#include "../lambda/apply.hpp"
6+
#include "../lambda/lambda.hpp"
7+
#include "../lambda/partial.hpp"
8+
#include "../number/if.hpp"
9+
#include "../value/fold_left.hpp"
10+
11+
namespace metal {
12+
namespace detail {
13+
template<bool>
14+
struct _min_element_binary_expr_guard {
15+
template<template<class...> class expr, class a, class b>
16+
using type = expr<a, b>;
17+
};
18+
19+
template<class...>
20+
struct _guard { // alternate version for arity n, but possibly(?) slower
21+
template<template<class...> class expr, class... args>
22+
using type = expr<args...>;
23+
};
24+
25+
template<typename lbd>
26+
struct _min_element {};
27+
28+
template<template<class...> class expr>
29+
struct _min_element<lambda<expr>> {
30+
template<class x, class y, class... empty>
31+
using combiner =
32+
if_<typename _min_element_binary_expr_guard<!sizeof...(
33+
empty)>::template type<expr, y, x>,
34+
y, x>;
35+
36+
template<class x, class y, class... _>
37+
using more_general_but_possibly_slower_combiner = // TODO: benchmark
38+
if_<typename _guard<_...>::template type<expr, y, x>, y, x>;
39+
40+
template<class seq>
41+
using type =
42+
apply<partial<lambda<fold_left>, lambda<combiner>>, seq>;
43+
};
44+
45+
} // detail
46+
47+
template<typename seq, typename lbd>
48+
using min_element = typename detail::_min_element<lbd>::template type<seq>;
49+
} // metal
50+
51+
#endif

0 commit comments

Comments
 (0)