В продолжение темы
Невероятно, но факт! Не константные значения в компайл-тайм!Автор: remark
Дата: 06.02.07
. Обещанный компайл-тайм счётчик.
Вот ядро счётчика:
int engine(...);
template<bool f> struct ts
{
typedef int type;
};
template<> struct ts<false>
{
typedef char type;
};
#ifndef COUNTER_MAX_COUNT
#define COUNTER_MAX_COUNT 100
#endif
#define COUNTER_HELPER(z, n, text) , typename ts<(v>n)>::type
template<typename type>
struct cnt_unique {};
template<typename, template <int> class, int> struct cnt;
typedef cnt<cnt_unique<cnt_unique<void> >, lin_gen, 0> cntt;
template
<
typename tag_t = void,
template <int> class gen_t = lin_gen,
int id = sizeof(engine(*(cntt*)0, *(cnt_unique<tag_t>*)0,
BOOST_PP_ENUM_PARAMS(COUNTER_MAX_COUNT, (int))))
>
struct cnt
{
static const int v = id / 4 - 1;
friend int(&engine(cntt&, cnt_unique<tag_t>& BOOST_PP_REPEAT(COUNTER_MAX_COUNT, COUNTER_HELPER, _)))[v+2];
static const int val = gen_t<v>::val;
};
Вот генераторы (свой добавить тривиально):
template<int id> struct lin_gen
{
static const int val = id;
};
template<int id> struct even_gen
{
static const int val = id * 2;
};
template<int id> struct lin_gen_down
{
static const int val = -id;
};
template<int id> struct pow2_gen
{
static const int val = 2 << id;
};
Вот функции получения текущего значения счётчика и прибавления числа к счётчику:
template
<
typename tag_t = void,
template <int> class gen_t = lin_gen,
int id = sizeof(engine(*(cntt*)0, *(cnt_unique<tag_t>*)0,
BOOST_PP_ENUM_PARAMS(COUNTER_MAX_COUNT, (int))))
>
struct cnt_cur
{
static const int v = id / 4 - 1;
static const int val = gen_t<v>::val;
};
template
<
int id,
unsigned int add,
typename tag_t,
template <int> class gen_t
>
struct cnt_add_helper : cnt_add_helper<id, add - 1, tag_t, gen_t>
{
static const int val = cnt<tag_t, gen_t>::val;
};
template
<
int id,
typename tag_t,
template <int> class gen_t
>
struct cnt_add_helper<id, 1, tag_t, gen_t>
{};
template
<
unsigned int add,
typename tag_t = void,
template <int> class gen_t = lin_gen,
int id = cnt<>::val
>
struct cnt_add : cnt_add_helper<id, add, tag_t, gen_t>
{
static const int val = cnt<tag_t, gen_t>::val;
};
Можно ещё сделать возможность декремента и вычитания для счётчика. Примерно таким макаром:
template
<
typename tag_t = void,
template <int> class gen_t = lin_gen,
int id = sizeof(engine(*(cntt*)0, *(cnt_unique<tag_t>*)0,
BOOST_PP_ENUM_PARAMS(COUNTER_MAX_COUNT, (int))))
- sizeof(engine2(*(cntt*)0, *(cnt_unique<tag_t>*)0,
BOOST_PP_ENUM_PARAMS(COUNTER_MAX_COUNT, (int))))
>
struct cnt ...
Тогда получится настоящий ct_var. Который можно использовать так:
struct my_var;
ct_var<my_var>::val;
ct_var<my_var>::inc::val;
ct_var<my_var>::dec::val;
ct_var<my_var>::add<5>::val;
ct_var<my_var>::sub<5>::val;