-
-
Save lonsdale8734/41ca464055df85e57f80fadaa44424f1 to your computer and use it in GitHub Desktop.
static range loop for c++ template. Idea from http://spraetor.github.io/2015/12/26/compile-time-loops.html
This file contains hidden or 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
| #include <type_traits> | |
| #include <utility> | |
| namespace detail | |
| { | |
| constexpr inline int Sgn(int v) | |
| { | |
| return (v > 0) - (v < 0); | |
| } | |
| template <int Start, int Stop, int Step, int...> | |
| class BasicStaticRange | |
| { | |
| public: | |
| static_assert(Step != 0, "Step cannot be 0."); | |
| template <class F> | |
| static inline void ForEach(F &&f) | |
| { | |
| InnerForEach(std::forward<F>(f)); | |
| } | |
| private: | |
| template <int I> | |
| using RangeIndex = std::integral_constant<int, I>; | |
| static constexpr bool VALID = ((Stop - Start) * Sgn(Step)) > 0; | |
| // Dummy enable SFINAE for enable_if | |
| template <class F, bool Dummy = true> | |
| static inline | |
| typename std::enable_if<VALID || Dummy && !Dummy, void>::type | |
| InnerForEach(F &&f) | |
| { | |
| f(RangeIndex<Start>()); | |
| BasicStaticRange<Start + Step, Stop, Step>::ForEach(std::forward<F>(f)); | |
| } | |
| template <class F, bool Dummy = true> | |
| static inline | |
| typename std::enable_if<!VALID || Dummy && !Dummy, void>::type | |
| InnerForEach(F &&f) | |
| { | |
| } | |
| }; | |
| template <int First, int... Others> | |
| class StaticRange | |
| { | |
| public: | |
| template <class F> | |
| static inline void ForEach(F &&f) | |
| { | |
| InnerForEach(std::forward<F>(f)); | |
| } | |
| private: | |
| static constexpr int N = sizeof...(Others); | |
| // static_assert( | |
| // N < 3, "StaticRange cannot be more than 3 template arguments"); | |
| // Dummy enable SFINAE for enable_if | |
| template <class F, bool Dummy = true> | |
| static inline | |
| typename std::enable_if<(N == 0 || Dummy && !Dummy), void>::type | |
| InnerForEach(F &&f) | |
| { | |
| BasicStaticRange<0, First, 1>::ForEach(std::forward<F>(f)); | |
| } | |
| template <class F, bool Dummy = true> | |
| static inline | |
| typename std::enable_if<(N == 1 || Dummy && !Dummy), void>::type | |
| InnerForEach(F &&f) | |
| { | |
| BasicStaticRange<First, Others..., 1>::ForEach(std::forward<F>(f)); | |
| } | |
| template <class F, bool Dummy = true> | |
| static inline | |
| typename std::enable_if<(N > 1 || Dummy && !Dummy), void>::type | |
| InnerForEach(F &&f) | |
| { | |
| BasicStaticRange<First, Others...>::ForEach(std::forward<F>(f)); | |
| } | |
| }; | |
| } // namespace detail | |
| /*********************************/ | |
| #include <iostream> | |
| using detail::StaticRange; | |
| template <int N> | |
| struct Printer | |
| { | |
| void Run() { std::cout << N << std::endl; } | |
| }; | |
| template <int N> | |
| void Print() | |
| { | |
| std::cout << N << std::endl; | |
| }; | |
| int main() | |
| { | |
| StaticRange<3>::ForEach([](auto I) { Print<I>(); }); | |
| std::cout << std::endl; | |
| StaticRange<4, 7>::ForEach([](auto I) { Printer<I>().Run(); }); | |
| std::cout << std::endl; | |
| StaticRange<8, 15, 3>::ForEach([](auto I) { Printer<I>().Run(); }); | |
| std::cout << std::endl; | |
| StaticRange<15, 20, 1, 10>::ForEach([](auto I) { Printer<I>().Run(); }); | |
| std::cout << std::endl; | |
| StaticRange<15, 10>::ForEach([](auto I) { Print<I>(); }); | |
| std::cout << std::endl; | |
| StaticRange<15, 10, -1>::ForEach([](auto I) { Print<I>(); }); | |
| std::cout << std::endl; | |
| StaticRange<15, 10, -2>::ForEach([](auto I) { Print<I>(); }); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment