[Trick] Компайл-тайм счётчик
От: remark Россия http://www.1024cores.net/
Дата: 06.02.07 21:29
Оценка: 77 (7)
В продолжение темы Невероятно, но факт! Не константные значения в компайл-тайм!
Автор: 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;



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.