Skip to content

Instantly share code, notes, and snippets.

@TartanLlama
Created June 28, 2016 08:40
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TartanLlama/3aa4541c12538d1d6cf5cf244cc5d724 to your computer and use it in GitHub Desktop.
Save TartanLlama/3aa4541c12538d1d6cf5cf244cc5d724 to your computer and use it in GitHub Desktop.
#include <utility>
#include <iostream>
#include <cstddef>
namespace atch { namespace {
template<class Tag>
struct meta_counter {
using size_type = std::size_t;
template<size_type N>
struct ident {
friend constexpr size_type adl_lookup (ident<N>);
static constexpr size_type value = N;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template<class Ident>
struct writer {
friend constexpr size_type adl_lookup (Ident) {
return Ident::value;
}
static constexpr size_type value = Ident::value;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template<size_type N, int = adl_lookup (ident<N> {})>
static constexpr size_type value_reader (int, ident<N>) {
return N;
}
template<size_type N>
static constexpr size_type value_reader (float, ident<N>, size_type R = value_reader (0, ident<N-1> ())) {
return R;
}
static constexpr size_type value_reader (float, ident<0>) {
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template<size_type Max = 64>
static constexpr size_type value (size_type R = value_reader (0, ident<Max> {})) {
return R;
}
template<size_type N = 1, class H = meta_counter>
static constexpr size_type next (size_type R = writer<ident<N + H::value ()>>::value) {
return R;
}
template<size_type N, class H = meta_counter>
static constexpr size_type write (size_type R = writer<ident<N + H::value() - H::value()>>::value) {
return R;
}
};
}}
template <std::size_t N>
using size_constant = std::integral_constant<std::size_t, N>;
using VarCounter = atch::meta_counter<class VarCount>;
template <class Counter = VarCounter,
class C = size_constant<Counter::next()>>
using next_var_tag = C;
template <class VarTag>
class integral_variable {
using size_type = std::size_t;
public:
using var_tag = VarTag;
template <std::size_t Var, std::size_t Assign>
struct assign_tag_{};
template <class C = atch::meta_counter<var_tag>, size_type R = C::next()>
static constexpr auto next_assign_tag(assign_tag_<var_tag::value, R> tag = {}) {
return tag;
}
template <class C = atch::meta_counter<var_tag>, size_type R = C::value()>
static constexpr auto assign_tag(assign_tag_<var_tag::value, R> tag = {}) {
return tag;
}
public:
template <class VarCount = atch::meta_counter<var_tag>, class Tag = decltype(assign_tag<VarCount>())>
constexpr size_type get(size_type R = atch::meta_counter<Tag>::template value()) {
return R;
}
template <size_type N, class VarCount = atch::meta_counter<var_tag>, class Tag = decltype(next_assign_tag<VarCount>())>
constexpr size_type set (size_type Written = atch::meta_counter<Tag>::template write<N>()) {
return Written;
}
};
template <std::size_t Init = 0,
class C = VarCounter,
class VarTag = size_constant<C::next()>>
constexpr auto make_integral_variable() {
auto v = integral_variable<VarTag>{};
v.template set<Init>();
return v;
}
int main () {
auto a = make_integral_variable();
auto b = make_integral_variable<3>();
static_assert(a.get() == 0, "wat");
static_assert(b.get() == 3, "wat");
a.set<12>();
b.set<5>();
static_assert(a.get() == 12, "wat");
static_assert(b.get() == 5, "wat");
}
@Manu343726
Copy link

Link to the article explaining this sorcery https://blog.tartanllama.xyz/integral_variable/

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