Невероятно, но факт! Не константные значения в компайл-тайм!
От: remark Россия http://www.1024cores.net/
Дата: 06.02.07 20:55
Оценка: 257 (23) -2 :)
Пришло время очередного ресёрча

В компайл-тайм все объекты константные. Будь то интегральные значения или типы. Т.е. имея запись:
const int i = some::val;
typedef some::type type;

всегда some::val будет иметь одно и то же значение и some::type будет одним и тем же типом. В принципе можно к этому добавить входные агрументы:
const int i = some<char, 5>::val;
typedef some<int, 15>::type type;

но результат всё равно всегда однозначно определяется входными значениями. Т.е. это фактически функциональный язык с константными объектами.

Так вот, всё это неправда!
Сейчас вы увидите, как на стандартном с++ можно иметь переменные значения в компайл-тайм!

char engine(...);

template<typename, int> struct magic;
typedef magic<char, -1> magicc;

template<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
struct magic
{
    friend int engine(magicc&, type&);
    static const int val = id;
};

int main()
{
    char a[magic<>::val != magic<>::val ? 1 : -1];
}






Код копилируется gcc4.1/msvc7.1/msvc8.0/edg c++

Вы скажете "Ну и что? Что с помощью этого можно сделать?"
Всё, что можно сделать, я пока не знаю, но знаю, что сделать можно много. Собственно для этого, в частности, я это и публикую, что бы общественность могла придумывать свои применения.

Вот какие применения я на данный момент придумал:

1. Компайл-тайм счётчик. Аналог __COUNTER__, тока лучше. Фичи:
— в любом месте можно завести свой "личный" экземпляр счётчика, т.е. он будет всегда начинать считать с нуля, а не с произвольного меняющегося числа.
— можно генерировать не только последовательность натуральных чисел, а произвольные последовательности: степени 2 (1, 2, 4, 8 ...), чётные числа (0, 2, 4, 6 ...), в сторону уменьшения (0, -1, -2, -3 ...) и т.д.
— если счётчик используется внутри шаблона, будет генерироваться новое значение для каждой специализации шаблона
— можно получить текущее значение счётчика, не инкрементируя его
— типизированный счётчик — выдаёт, например, значения типа short

Примеры использования:

// Просто получаем значение счётчика
int i = cnt<>::val;

// Заводим "личный" счётчик
struct my_tag;
int j = cnt<my_tag>::val;

// Генерируем последовательность степеней двойки
struct my_tag2;
enum x
{
  val1 = cnt<my_tag2, pow2gen>::val,
  val2 = cnt<my_tag2, pow2gen>::val,
  val3 = cnt<my_tag2, pow2gen>::val
};



2. Компайл-тайм генератор случайных чисел.
Никаких особых фич и распределений я не делал. Пример использования:

// Создали массив из 3 случайных чисел от 5 до 20 
int data[] = {rnd<5, 20>::val, rnd<5, 20>::val, rnd<5, 20>::val};



3. ... не знаю как назвать... легче на примере показать. Допустим есть класс:

struct person
{
    prop<person, int> m1;
    prop<person, char> m2;
    prop<person, std::string> m3;
    prop<person, char> m4;
    prop<person, int> m5;
};


Каждый член класса в компайл-тайм получает значение смещения себя относительно объемлющего объекта. Т.е. фактически получается что-то типа следующего:

struct person
{
    prop<person, int, 0> m1;
    prop<person, char, 5> m2;
    prop<person, std::string, 8> m3;
    prop<person, char, 40> m4;
    prop<person, int, 44> m5;
};


Как это работает? Заводится приватный счётчик (cnt<person>). Каждый член получает текущее значение этого счётчика — это есть его смещение. Далее инкрементирует счётчик на свой размер. И уаля. В реальности ещё приходится делать поправку на выравнивание, но это уже детали.
Это даёт возможность членам обращаться к своему контейнеру и наоборот.
Добавляем к этому регистрацию типов (здесь
Автор:
Дата: 26.12.06
или здесь
Автор: Chez
Дата: 28.03.05
) и получаем не больше и не меньше, а compile-time reflection!!!
Для такого класса мы знаем порядок, типы и смещения членов — реализация, например, бинарной сериализации далее видится тривиальной


4. Это переводит
[Trick] Автоматическое определение неиспользуемых заголовков
Автор: remark
Дата: 21.01.07

[Trick] Форсирование правильного использования библиотеки
Автор: remark
Дата: 21.01.07

[Trick] Форсирование проверки возвращаемого значения
Автор: remark
Дата: 24.12.06

из разряда M$ SPECIFIC в 100% PURE C++



Дальше у кого на сколько хватит фантазии
Код указанных фич я приведу в отдельных постах, что бы сюда слишком много не мешать.


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