Skip to content

Instantly share code, notes, and snippets.

@lonsdale8734
Last active October 12, 2020 12:13
Show Gist options
  • Select an option

  • Save lonsdale8734/41ca464055df85e57f80fadaa44424f1 to your computer and use it in GitHub Desktop.

Select an option

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
#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