5
5
#include < utility>
6
6
7
7
namespace bb {
8
+ namespace detail {
9
+
10
+ /* *
11
+ * @brief Create an index sequence from Min to Max (not included) with an increment of Inc
12
+ */
13
+ template <size_t Min, size_t Max, size_t Inc> constexpr auto make_index_range ()
14
+ {
15
+ static_assert (Max >= Min);
16
+ static_assert (Inc >= 1 );
17
+ return []<size_t ... Is>(std::index_sequence<Is...>) {
18
+ return std::index_sequence<Min + (Is * Inc)...>{};
19
+ }(std::make_index_sequence<(Max - Min - 1 ) / Inc + 1 >{});
20
+ }
21
+
22
+ } // namespace detail
8
23
9
24
/* *
10
25
* @brief Implements a loop using a compile-time iterator. Requires c++20.
@@ -55,37 +70,11 @@ namespace bb {
55
70
*/
56
71
template <size_t Start, size_t End, size_t Inc, class F > constexpr void constexpr_for (F&& f)
57
72
{
58
- // Call function `f<Start>()` iff Start < End
59
- if constexpr (Start < End) {
60
- // F must be a template lambda with a single **typed** template parameter that represents the iterator
61
- // (e.g. [&]<size_t i>(){ ... } is good)
62
- // (and [&]<typename i>(){ ... } won't compile!)
63
-
64
- /* *
65
- * Explaining f.template operator()<Start>()
66
- *
67
- * The following line must explicitly tell the compiler that <Start> is a template parameter by using the
68
- * `template` keyword.
69
- * (if we wrote f<Start>(), the compiler could legitimately interpret `<` as a less than symbol)
70
- *
71
- * The fragment `f.template` tells the compiler that we're calling a *templated* member of `f`.
72
- * The "member" being called is the function operator, `operator()`, which must be explicitly provided
73
- * (for any function X, `X(args)` is an alias for `X.operator()(args)`)
74
- * The compiler has no alias `X.template <tparam>(args)` for `X.template operator()<tparam>(args)` so we must
75
- * write it explicitly here
76
- *
77
- * To summarize what the next line tells the compiler...
78
- * 1. I want to call a member of `f` that expects one or more template parameters
79
- * 2. The member of `f` that I want to call is the function operator
80
- * 3. The template parameter is `Start`
81
- * 4. The function operator itself contains no arguments
82
- */
83
- f.template operator ()<Start>();
84
-
85
- // Once we have executed `f`, we recursively call the `constexpr_for` function, increasing the value of `Start`
86
- // by `Inc`
87
- constexpr_for<Start + Inc, End, Inc>(f);
88
- }
73
+ // F must be a template lambda with a single **typed** template parameter that represents the iterator
74
+ // (e.g. [&]<size_t i>(){ ... } is good)
75
+ // (and [&]<typename i>(){ ... } won't compile!)
76
+ constexpr auto indices = detail::make_index_range<Start, End, Inc>();
77
+ [&]<size_t ... Is>(std::index_sequence<Is...>) { (f.template operator ()<Is>(), ...); }(indices);
89
78
}
90
79
91
80
}; // namespace bb
0 commit comments