Привет всем!
Сразу огромное спасибо vopl за наводку:
http://rsdn.org/forum/cpp/8849463.1Автор: vopl
Дата: 08.11 11:41
Благодаря этому финту с энтропией, удалось получить новую имплементацию компайл-тайм счётчика, лишённую ВСЕХ недостатков, присущих предыдущим версиям. Новый счетчик представляет собой простой шаблон переменной, параметризуемый произвольным типом (т.е. каждый счётчик привязывается к определенному типу). Счётчики можно применять в любых областях видимости (неймспейс, функция, класс). И главное — данная реализация вообще не использует препроцессор!
Вот здесь, собственно, вся реализация:
http://coliru.stacked-crooked.com/a/2f1f2e2384a2031d
#include <iostream>
namespace compile_time
{
template <typename T, typename E = decltype([] {}) >
concept Complete = requires {
{sizeof(T)};
typename E;
};
template <typename T, typename E = decltype([] {}) >
concept Incomplete = !Complete<T, E>;
template <typename T, size_t I>
struct Declaration { friend constexpr auto test(Declaration); };
template <typename T, size_t I>
struct Definition {
friend constexpr auto test(Declaration<T, I>) { return I; }
friend constexpr auto test(Definition) { return test(Declaration<T, I>{}); }
};
template <typename T, size_t I, typename E = decltype([] {}) >
concept Defined = Complete<decltype(test(Declaration<T, I>{})), E > ;
template <typename T, size_t I, typename E = decltype([] {}) >
concept Undefined = !Defined<T, I, E>;
template <typename T, size_t I, typename E = decltype([] {}) >
struct FindCurrentFrom : FindCurrentFrom<T, I + 1, E> {};
template <typename T, size_t I, typename E>
requires Undefined<T, I, E>
struct FindCurrentFrom<T, I, E> : std::integral_constant<size_t, I> {};
template <typename T, typename E = decltype([] {}) >
inline constexpr size_t ct_peek = FindCurrentFrom<T, 0, E>::value;
template <typename T, typename E = decltype([] {}) >
inline constexpr size_t ct_tick = test(Definition<T, ct_peek<T, E>>{});
} // namespace compile_time
using compile_time::ct_peek;
using compile_time::ct_tick;
int main()
{
static_assert(ct_tick<int> == 0);
static_assert(ct_tick<class X> == 0);
static_assert(ct_tick<void> == 0);
struct Inner
{
static_assert(ct_tick<int> == 1);
static_assert(ct_tick<class X> == 1);
static_assert(ct_tick<void> == 1);
static_assert(ct_peek<int> == 2);
static_assert(ct_peek<class X> == 2);
static_assert(ct_peek<void> == 2);
};
static_assert(ct_tick<int> == 2);
static_assert(ct_tick<class X> == 2);
static_assert(ct_tick<void> == 2);
static_assert(ct_tick<int> == 3);
static_assert(ct_tick<class X> == 3);
static_assert(ct_tick<void> == 3);
}