Skip to content

Instantly share code, notes, and snippets.

@talybin
Last active September 19, 2021 20:08
Show Gist options
  • Save talybin/3fce910030a19b311febb1ba07335156 to your computer and use it in GitHub Desktop.
Save talybin/3fce910030a19b311febb1ba07335156 to your computer and use it in GitHub Desktop.
Constant expression counter
namespace detail
{
template <class T>
struct flag
{
struct dummy {
constexpr dummy() {}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnon-template-friend"
friend constexpr void adl_flag(dummy);
#pragma GCC diagnostic pop
};
template <bool>
struct writer {
friend constexpr void adl_flag(dummy) {}
};
template <class Dummy, int = (adl_flag(Dummy{}), 0)>
static constexpr bool check(int) {
return true;
}
template <class Dummy>
static constexpr bool check(short) {
return false;
}
template <class Dummy = dummy, bool Value = check<Dummy>(0)>
static constexpr bool read_set() {
return (writer<Value && 0>{}, Value);
}
template <class Dummy = dummy, bool Value = check<Dummy>(0)>
static constexpr bool read() {
return Value;
}
};
template <class T, int I>
struct tag {};
template <class T, int N, int Step, bool B>
struct checker {
static constexpr int currentval() noexcept {
return N;
}
};
template <class T, int N, int Step>
struct checker_wrapper {
template <bool B = flag<tag<T, N>>{}.read(), int M = checker<T, N, Step, B>{}.currentval()>
static constexpr int currentval() {
return M;
}
};
template <class T, int N, int Step>
struct checker<T, N, Step, true> {
template <int M = checker_wrapper<T, N + Step, Step>{}.currentval()>
static constexpr int currentval() noexcept {
return M;
}
};
template <class T, int N, bool B = flag<tag<T, N>>{}.read_set()>
struct next {
static constexpr int value() noexcept {
return N;
}
};
} // namespace detail
template <class Tag = void, int Start = 0, int Step = 1>
struct constexpr_counter
{
template <int N = detail::checker_wrapper<Tag, Start, Step>{}.currentval()>
static constexpr int value() {
return N;
}
template <int N = value()>
static constexpr int next() {
return detail::next<Tag, N>{}.value() + Step;
}
};
#include "constexpr_counter.hpp"
int main()
{
using counter_A_0_1 = constexpr_counter<struct TagA, 0, 1>;
static_assert(counter_A_0_1::value() == 0);
constexpr int a0 = counter_A_0_1::next();
static_assert(counter_A_0_1::value() == 1);
constexpr int a1 = counter_A_0_1::next();
static_assert(counter_A_0_1::value() == 2);
constexpr int a2 = counter_A_0_1::next();
static_assert(counter_A_0_1::value() == 3);
static_assert(a0 == 1);
static_assert(a1 == 2);
static_assert(a2 == 3);
using counter_B_0_1 = constexpr_counter<struct TagB, 0, 1>;
constexpr int b0 = counter_B_0_1::next();
constexpr int b1 = counter_B_0_1::next();
constexpr int b2 = counter_B_0_1::next();
static_assert(b0 == 1);
static_assert(b1 == 2);
static_assert(b2 == 3);
using counter_C_2_1 = constexpr_counter<struct TagC, 2, 1>;
static_assert(counter_C_2_1::value() == 2);
constexpr int c0 = counter_C_2_1::next();
constexpr int c1 = counter_C_2_1::next();
constexpr int c2 = counter_C_2_1::next();
static_assert(c0 == 3);
static_assert(c1 == 4);
static_assert(c2 == 5);
using counter_D_4_1 = constexpr_counter<struct TagD, 4, 1>;
static_assert(counter_D_4_1::value() == 4);
constexpr int d0 = counter_D_4_1::next();
constexpr int d1 = counter_D_4_1::next();
constexpr int d2 = counter_D_4_1::next();
static_assert(d0 == 5);
static_assert(d1 == 6);
static_assert(d2 == 7);
using counter_E_5_3 = constexpr_counter<struct TagE, 5, 3>;
static_assert(counter_E_5_3::value() == 5);
constexpr int e0 = counter_E_5_3::next();
constexpr int e1 = counter_E_5_3::next();
constexpr int e2 = counter_E_5_3::next();
static_assert(e0 == 8);
static_assert(e1 == 11);
static_assert(e2 == 14);
using counter_F_2_m3 = constexpr_counter<struct TagF, 2, -3>;
static_assert(counter_F_2_m3::value() == 2);
constexpr int f0 = counter_F_2_m3::next();
constexpr int f1 = counter_F_2_m3::next();
constexpr int f2 = counter_F_2_m3::next();
static_assert(f0 == -1);
static_assert(f1 == -4);
static_assert(f2 == -7);
}
@talybin
Copy link
Author

talybin commented Aug 22, 2021

Warning:
Should NOT be used in production code. Stateful metaprogramming is not intended to be allowed by the standard, so don't be surprised if the standard is changed to invalidate any of above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment