В компайл-тайм все объекты константные. Будь то интегральные значения или типы. Т.е. имея запись:
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. ... не знаю как назвать... легче на примере показать. Допустим есть класс:
Как это работает? Заводится приватный счётчик (cnt<person>). Каждый член получает текущее значение этого счётчика — это есть его смещение. Далее инкрементирует счётчик на свой размер. И уаля. В реальности ещё приходится делать поправку на выравнивание, но это уже детали.
Это даёт возможность членам обращаться к своему контейнеру и наоборот.
Добавляем к этому регистрацию типов (здесь
) и получаем не больше и не меньше, а compile-time reflection!!!
Для такого класса мы знаем порядок, типы и смещения членов — реализация, например, бинарной сериализации далее видится тривиальной
Здравствуйте, remark, Вы писали:
R>Сейчас вы увидите, как на стандартном с++ можно иметь переменные значения в компайл-тайм!
R>
R>char engine(...);
R>template<typename, int> struct magic;
R>typedef magic<char, -1> magicc;
R>template<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
R>struct magic
R>{
R> friend int engine(magicc&, type&);
R> static const int val = id;
R>};
R>int main()
R>{
R> char a[magic<>::val != magic<>::val ? 1 : -1];
R>}
R>
Хм... Оригинально, но не понятно, должно ли это работать так, как задумано. Как известно, friend declaration не вводит в охватывающий namespace видимого имени. Поэтому не ясно, почему в твоем случае при второй инстанциации 'magic' lookup для дефолтного аргумента вдруг должно найти именно "друга", а не явно объявленную оригинальную версию 'engine'...
На Comeau Online — не работает. А именно, оба 'magic<>::val' одинаковы.
Best regards,
Андрей Тарасевич
Re: Невероятно, но факт! Не константные значения в компайл-т
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Хм... Оригинально, но не понятно, должно ли это работать так, как задумано. Как известно, friend declaration не вводит в охватывающий namespace видимого имени. Поэтому не ясно, почему в твоем случае при второй инстанциации 'magic' lookup для дефолтного аргумента вдруг должно найти именно "друга", а не явно объявленную оригинальную версию 'engine'...
Да, friend declaration не вводит в охватывающий namespace видимого имени. Всё правильно. Над этой проблемой пришлось побороться.
На помощь пришёл ADL! Смотри:
Это же работает, хотя тоже вроде как не должно, т.к. operator + () вообще говоря не виден вне класса.
Поэтому я добавил в функцию engine() параметр magic&! Теперь она тоже попадает в рассмотрение!
АТ>На Comeau Online — не работает. А именно, оба 'magic<>::val' одинаковы.
Здравствуйте, Roman Odaisky, Вы писали:
RO>Здравствуйте, remark, Вы писали:
R>>Пришло время очередного ресёрча
RO>Я попробовал на VC9, только первые 2 значения разные
Во-первых, это уже круто!
Во-вторых, что такое VC9
В-третих, Да, всё правильно, тут я только для двух сделал, что бы было хоть чуть-чуть понятно как работает
Здравствуйте, IROV.., Вы писали:
IRO>Будь проще и люди подтянутся
А зачем они мне?
IRO>А то что только первое и второе вхождение будет, видно из кода, точнее из за механизма!
Да, тут я привёл только для двух, что бы было понятнее. Смотри здесь
для полной версии счётчика.
IRO>Вся ботва в двух ключевых моментах а именно
IRO>char engine( ... ); // выбор данной функции при перегрузке всегда последния (скока можно красивых вещей на этом сделать)
Не понял, что имеется в виду...
Да, engine(...), имеет наименьший приоритет при выборе перегрузок, на этом всё и построено...
IRO>и то что sizeof() не ищет реализацию а только оглавление.
Опять не понял...
IRO>Комеаут скорее всего не работает так как надо, потомучто он не успел найти обявление friend int engine(_true);
Да, Комеаут не работает, я знаю, но это не ко мне, а к нему
Здравствуйте, remark, Вы писали:
R>Здравствуйте, IROV.., Вы писали:
IRO>>Будь проще и люди подтянутся R>А зачем они мне?
А в прочем ты прав _люди_ такое не используют
IRO>>А то что только первое и второе вхождение будет, видно из кода, точнее из за механизма!
R>Да, тут я привёл только для двух, что бы было понятнее. Смотри здесь
Здравствуйте, IROV.., Вы писали:
IRO>Здравствуйте, remark, Вы писали:
R>>Здравствуйте, IROV.., Вы писали:
IRO>>>Будь проще и люди подтянутся R>>А зачем они мне? IRO>А в прочем ты прав _люди_ такое не используют
Я никого не принуждаю это использовать, и даже читать не принуждаю...
IRO>>>А то что только первое и второе вхождение будет, видно из кода, точнее из за механизма!
R>>Да, тут я привёл только для двух, что бы было понятнее. Смотри здесь
Здравствуйте, remark, Вы писали:
R>3. ... не знаю как назвать... легче на примере показать. Допустим есть класс:
R>В реальности ещё приходится делать поправку на выравнивание, но это уже детали.
Каким образом делается поправка на выравнивание?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Re[4]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Аноним, Вы писали:
А>Т.е. поиск имен, по-твоему, зависит от того, сколько ты раз написал magic<> ?
поиск имен зависит от того, какие аргументы принимает функция.
если функия принимает аргументом magic, то поиск подходящей функции будет происходит и в пространстве magic.
до инстанцирования magic<-1> есть только engine(...);
после добавляется engine(magic<-1>);
А>Или я не так тебя понял?
похоже на то.
Re[5]: Невероятно, но факт! Не константные значения в компай
От:
Аноним
Дата:
07.02.07 10:12
Оценка:
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, Аноним, Вы писали:
А>>Т.е. поиск имен, по-твоему, зависит от того, сколько ты раз написал magic<> ?
NB>поиск имен зависит от того, какие аргументы принимает функция. NB>если функия принимает аргументом magic, то поиск подходящей функции будет происходит и в пространстве magic.
NB>до инстанцирования magic<-1> есть только engine(...); NB>после добавляется engine(magic<-1>);
А ты не думал, что поиск имен не зависит от инстанцирования и вещи это ортогональные?
А>>Или я не так тебя понял?
NB>похоже на то.
Ну так поясни, почему похоже. Т.е. по твоим представлениям, С++ это язык в котором
void fun()
{
name;
name;
}
поиск имени name зависит от того, в какой оно строке стоит?
Re: Невероятно, но факт! Не константные значения в компайл-т
R>char engine(...);
R>template<typename, int> struct magic;
R>typedef magic<char, -1> magicc;
R>template<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
R>struct magic
R>{
R> friend int engine(magicc&, type&);
R> static const int val = id;
R>};
R>int main()
R>{
R> char a[magic<>::val != magic<>::val ? 1 : -1];
R>}
R>
[]
как я понял каждое выражение magic<>::val должно инстанциировать magic заново и sizeof(engine(*(magicc*)0, *(type*)0)) выдавать новые значение?
Все равно не очень понятно
Re: Невероятно, но факт! Не константные значения в компайл-т
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>>Хм... Оригинально, но не понятно, должно ли это работать так, как задумано. Как известно, friend declaration не вводит в охватывающий namespace видимого имени. Поэтому не ясно, почему в твоем случае при второй инстанциации 'magic' lookup для дефолтного аргумента вдруг должно найти именно "друга", а не явно объявленную оригинальную версию 'engine'...
R>Да, friend declaration не вводит в охватывающий namespace видимого имени. Всё правильно. Над этой проблемой пришлось побороться. R>На помощь пришёл ADL! Смотри:
R>
R>Это же работает, хотя тоже вроде как не должно, т.к. operator + () вообще говоря не виден вне класса.
R>Поэтому я добавил в функцию engine() параметр magic&! Теперь она тоже попадает в рассмотрение!
С чего бы это? У тебя тип параметра не совпадает с типом, в котором продекларирован engine().