Created
June 28, 2016 08:40
-
-
Save TartanLlama/3aa4541c12538d1d6cf5cf244cc5d724 to your computer and use it in GitHub Desktop.
This file contains 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 <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"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Link to the article explaining this sorcery https://blog.tartanllama.xyz/integral_variable/