Comments 64
Да, это именно то, чего мне не хватало все эти года :-) Если бы каждый программист как-можно больше фич реализовывал с помощью шаблонов — мы жили бы в чудесном мире производительности и ослепительного света прогресса.
+2
Прошу прощение, при всем моем уважении к вам — либо у вас сперли аккаунт, либо вы написали бота ) Столько BarsMonster'a на Хабре и в таком формате Мир еще не видывал. Смайлик из прошлого, практически в каждом посте — первый же комментарий, комментарии уровня среднестатистического хабрапетросяна вместо адекватных ответов (с вашим то багажом знаний, блин), топики уровня «поправим пару строк в виндовом реестре на питоне» & etc. Где старый добрый профи с клевым доменом в одной руке и симпатичной сестрой в другой? Неужели ППА головного мозга? Или рейтинг?
Сорри за выхлоп.
Сорри за выхлоп.
+14
+2
Да ладно :-)
Чем больше я там, тем больше хочется прибить акк (или сделать свой с блекджеком).
Есть всего один топик, который я действительно хочу опубликовать.
Чем больше я там, тем больше хочется прибить акк (или сделать свой с блекджеком).
Есть всего один топик, который я действительно хочу опубликовать.
0
Чего? Рейтинг на Хабре ведь ни к чему не обязывает. Ну первый ты, ну тысячный, никакой разницы, имхо)
Топики надо публиковать от души, имхо)
Топики надо публиковать от души, имхо)
+2
Вот, ты живешь в чудесном мире, и я рад за тебя :-)
0
Не, ну честно, а какая разница то?)
0
Все банально — для одной из будущих статей нужно быть на первом месте. Ну и мне понравилось как сестра случайно обнаружила меня на первом месте и была в полном шоке :-) — впрочем, это уже не повториться…
Самолюбие это само собой не тешит — т.к. на хабре достаточно несложно выйти на первое место — нужно просто подарить много-много своего времени(даже уметь программировать совершенно не обязательно). А дороже времени для меня ничего нет.
Самолюбие это само собой не тешит — т.к. на хабре достаточно несложно выйти на первое место — нужно просто подарить много-много своего времени(даже уметь программировать совершенно не обязательно). А дороже времени для меня ничего нет.
+1
Я имею ввиду другое
Чего? Чем так плохо первое место? Оно что есть, что нету.
Чем больше я там, тем больше хочется прибить акк (или сделать свой с блекджеком).
Чего? Чем так плохо первое место? Оно что есть, что нету.
0
Оно что есть, что нету если оно не нужно. А если нужно — тогда это как стоять в середине горной реки :-)
+1
Вот это мысль верная.
+3
Да-да, сперли :-) Бота все хотел — но пока никак.
ППА мне не светит, я по прежнему хочу от неё отказаться.
Насчет уровня можно спорить, но не публично. В данном конкретном случае — вырвалось моя личная неприязнь к злоупотреблению языком — последствия тяжелого детства.
ППА мне не светит, я по прежнему хочу от неё отказаться.
Насчет уровня можно спорить, но не публично. В данном конкретном случае — вырвалось моя личная неприязнь к злоупотреблению языком — последствия тяжелого детства.
0
А чего буквы такие маленькие? Стесняетесь что-ли?
0
Ну, все вроде бы супер! Только, в течении 10 минут пытался ответить себе на вопрос — «Где бы мне это понадобилось?». Или пятница-ночь, или я не дорос пока:)
+3
Александреску и другие замечательно показывают где и зачем. Boost и STL так же.
+2
Если Вы говорите про метапрограммирование, то оно должно сохранять принципы обобщенного программирования, а в приведенных примерах, я обобщенности не увидел. Но, это как в том бородатом анекдоте: "...-Видишь зайца? — Нет. -Вот и я не вижу, а он есть!":) Буду читать Александреску.
+1
Без осмысления тривиальных примеров не стоит даже открывать Александреску.
Пост является затравкой для привлечения народа к теме + возможный обмен опытом, но никак не best practices и им подобные. Для последнего лучше читать книги Александреску.
Пост является затравкой для привлечения народа к теме + возможный обмен опытом, но никак не best practices и им подобные. Для последнего лучше читать книги Александреску.
-2
А с чего вы решили, что оно кому-то что-то должно? Оно есть, у него свои возможности, как их использовать — дело каждого.
Читайте, читайте, там много полезного.
Читайте, читайте, там много полезного.
0
Такие фокусы как правило используются в библиотеках типа boost для организации несвойственных языку вещей — делегатов, грамматик, кортежей и иже с ними. Грамотная реализация того же делегата требует достаточно сложной шаблонной магии O_O.
0
шаблоны должны остаться шаблонами, а не задачкой для реализации машины Тьюринга ))
+13
Как ещё предлагаете заниматься мета-программированием в C++? Ведь это банальное управление генерацией кода, которое рано или поздно понадобится в каком-нибудь сложном софте. C++ — не Lisp, AST-макросов там нет. Выкручиваемся, как можем.
0
так где же это может пригодиться за рамками истинного предназначения шаблонов (коллекции, алгоритмы, итераторы и т.п.)? может стоит воспользоваться специализированными инструментами? например, ORM-генераторы классов, если таковые необходимы.
+1
Истинное предназначение шаблонов — удобная и упрощающая разработку генерация кода.
0
с чего вы взяли, что шаблоны C++ код генерят?
-3
Есть и те, что непосредственно не генерят. Но, в конечном счёте, они служат именно этой цели: шаблоны обобщают алгоритмы и структуры данных и служат для генерации специализированных версий этих алгоритмов и структур. А это, в свою очередь, позволяет выполнять некоторые вычисления на этапе компиляции, что есть неявная генерация кода. Похоже, вы воспринимаете термин «генерация кода» на слишком очевидном уровне: сгенерить из C++ машинный код.
+1
так всё же, какие вычисления на этапе компиляции необходимы, кроме вычисления типа? я уже второй раз прошу дать пример, имеющий смысл в реальном проекте, если он имеется. в теории все мне понятно. я тоже эту головоломку решал с факториалами, но практического значения в этих «выкрутасах» так и не увидел.
+2
пример: есть подсистема Property, поддерживает из коробки любые типы. Для того чтобы зарегестрировать в системе свойство нужно вызвать MakeProperty:
class CMyObject: public CPropertyEnabled
{
int a;
double x;
std::vector v;
DECLARE_META_CLASS();
};
…
IMPLEMENT_META_CLASS( CMyObject )
{
// Здесь мы задаем список свойст, поддерживаемых нашим классом
RegisterProperty( MakeProperty( &CMyObject::a, «a» ).release() );
RegisterProperty( MakeProperty( &CMyObject::x, «x» ).release() );
RegisterProperty( MakeProperty( &CMyObject::v, «v» ).release() );
}
// а вот так свойствами можно пользоваться:
CMyObject obj;
MakeTransaction().MakeTrampoline( &obj )
.SetPropertyValue( «a», 1 )
.SetPropertyValue( «x», «1.0» )
.SetPropertyValue( «v», "{1,2,3}" )
.Close();
assert( obj.a == 1 );
assert( obj.x == 1.0 );
assert( obj.v[0] == 1 );
assert( obj.v[1] == 2 );
assert( obj.v[1] == 3 );
А теперь обратите внимание, на то, что
1. RegisterProperty( MakeProperty(… ).release() ) выглядит абсолютно одинаково для свойств совершенно разных типов (у нас в с++ строгая типизация, напомню).
2. Каким-то магическим образом SetProperty может принимать не только реальный тип свойства, но и что-то, что можно в него адекватно сконвертировать (например, строку «1.5» в число 1.5)
3. Свойства контейнерных типов можно использовать так же как и сами контейнеры (но все обращения будут при этом идти через транзакцию, которую можно откатить):
auto oTransaction = MakeTransaction();
auto &rv = oTransaction.MakeTrampoline( &obj, «v» );
std::for_each( rv->begin(), rv->end(), [](… &r ){ r = (int)r + 1; } );
Так вот, это работает, потому как MakeProperty штука хитрая, при компиляции это:
RegisterProperty( MakeProperty( &CMyObject::a, «a» ).release() );
преобразуется приблизительно в следующее:
RegisterProperty(
MakeEmptyProperty( «a» )
.SetSetter( []( CMyObject *p, int v ){ p->a = v; } ) // как устанавливать свойство
.SetGetter( []( const CMyObject *p ){ return p->a; } ) // как читать свойство
.RegisterConversionTrampoline< std::string, int >(… ) // преобразование string->int
.RegisterConversionTrampoline< int, std::string >(… ) // преобразование string->int
.release() );
(трамплинов преобразований на самом деле больше, для контейнеров дополнительно устанавливаются функции, позволяющие получить begin, end, конкретный элемент, и т.п.)
так вот MakeProperty работает на шаблонах: анализируя переданный ей тип она старается как можно более точно описать, как генерировать для него свойства:
* если тип поддерживает сериализацию через стримы, зарегестрировать преобразователи из/в строковые типа
* если тип является константным не регестрировать setter (тогда свойство будет ридонли)
* если тип контейнер, зарегестрировать логику, специфичную для контейнеров и т.п.
class CMyObject: public CPropertyEnabled
{
int a;
double x;
std::vector v;
DECLARE_META_CLASS();
};
…
IMPLEMENT_META_CLASS( CMyObject )
{
// Здесь мы задаем список свойст, поддерживаемых нашим классом
RegisterProperty( MakeProperty( &CMyObject::a, «a» ).release() );
RegisterProperty( MakeProperty( &CMyObject::x, «x» ).release() );
RegisterProperty( MakeProperty( &CMyObject::v, «v» ).release() );
}
// а вот так свойствами можно пользоваться:
CMyObject obj;
MakeTransaction().MakeTrampoline( &obj )
.SetPropertyValue( «a», 1 )
.SetPropertyValue( «x», «1.0» )
.SetPropertyValue( «v», "{1,2,3}" )
.Close();
assert( obj.a == 1 );
assert( obj.x == 1.0 );
assert( obj.v[0] == 1 );
assert( obj.v[1] == 2 );
assert( obj.v[1] == 3 );
А теперь обратите внимание, на то, что
1. RegisterProperty( MakeProperty(… ).release() ) выглядит абсолютно одинаково для свойств совершенно разных типов (у нас в с++ строгая типизация, напомню).
2. Каким-то магическим образом SetProperty может принимать не только реальный тип свойства, но и что-то, что можно в него адекватно сконвертировать (например, строку «1.5» в число 1.5)
3. Свойства контейнерных типов можно использовать так же как и сами контейнеры (но все обращения будут при этом идти через транзакцию, которую можно откатить):
auto oTransaction = MakeTransaction();
auto &rv = oTransaction.MakeTrampoline( &obj, «v» );
std::for_each( rv->begin(), rv->end(), [](… &r ){ r = (int)r + 1; } );
Так вот, это работает, потому как MakeProperty штука хитрая, при компиляции это:
RegisterProperty( MakeProperty( &CMyObject::a, «a» ).release() );
преобразуется приблизительно в следующее:
RegisterProperty(
MakeEmptyProperty( «a» )
.SetSetter( []( CMyObject *p, int v ){ p->a = v; } ) // как устанавливать свойство
.SetGetter( []( const CMyObject *p ){ return p->a; } ) // как читать свойство
.RegisterConversionTrampoline< std::string, int >(… ) // преобразование string->int
.RegisterConversionTrampoline< int, std::string >(… ) // преобразование string->int
.release() );
(трамплинов преобразований на самом деле больше, для контейнеров дополнительно устанавливаются функции, позволяющие получить begin, end, конкретный элемент, и т.п.)
так вот MakeProperty работает на шаблонах: анализируя переданный ей тип она старается как можно более точно описать, как генерировать для него свойства:
* если тип поддерживает сериализацию через стримы, зарегестрировать преобразователи из/в строковые типа
* если тип является константным не регестрировать setter (тогда свойство будет ридонли)
* если тип контейнер, зарегестрировать логику, специфичную для контейнеров и т.п.
+1
шаблоны — полный по тьюрингу чисто функциональный язык, оперирующий типами. с помощью шаблонов генерируются новые типы классов.
+2
кроме вычисления типа и генерации классов (методов, функций) нужны ли еще какие-то возможности от шаблонов? я думаю, что нет. так как при технической возможности вычислять факториал на этапе компиляции, затраты на реализацию подобного простейшего алгоритма чудовищны. проще отдельный генератор написать, если так уж необходимо генерировать исходный код. свою же шаблонную роль шаблоны отлично выполняют ))
0
Вот тут: www.oonumerics.org/blitz/examples/fft.html вычисляют Fast Fourier Transform на этапе компиляции.
+7
Вот ещё подобный топик про CRC32:
habrahabr.ru/blogs/crazydev/38622/
habrahabr.ru/blogs/crazydev/38622/
0
А смысл? Если мне нужно вычислить преобразование фурье некоего константного сигнала, я пишу простую и понятную программку (без всякой там шаблонной магии), с обычными циклами, а результат просто забиваю в Си-шный массив. Смысл мозг пудрить?
+2
Да и вообще, по ссылке не вычисляют FFT, а разворачивают в линейный код — это большая разница.
0
Если таки вы попробуете сказать
специализация для дабла не сгенерится, а сгенерится ошибка компиляции. В случае вашего шаблона придётся писать:
min(2.0, 3)
специализация для дабла не сгенерится, а сгенерится ошибка компиляции. В случае вашего шаблона придётся писать:
min<double>(2.0, 3)
0
UFO just landed and posted this here
Ну дык, факториал на шаблонах и есть забава. Но вообще шаблонное мегапрограммирование попрошу не трогать!
0
UFO just landed and posted this here
Пошли на мою работу сходим, подебажим и порефакторим твои любимые шаблоны ;-)
Только нужно учитывать, что за рабочий день мы проект собрать сможем только 1 раз ;-)
Только нужно учитывать, что за рабочий день мы проект собрать сможем только 1 раз ;-)
0
Спасибо, Кэп! (простите, не сдержался)
+5
Как-то давно, узнав о такой возможности, написал вычисления определителя матрицы в compile-time.
Кстати, интересно, что МП на шаблонах в Си++ — чистый функциональный язык.
Кстати, интересно, что МП на шаблонах в Си++ — чистый функциональный язык.
+1
ага, только при оптимизациях и функция вычисляющая факториал редуцируется до своего значения, а вашу байду нельзя применить для переменных
This is useless, sad but true
This is useless, sad but true
+2
У Васи было два компьютера. Один он выбросил в окно. Сколько компьютеров осталось у Васи?
Вроде всё правильно, но бессмыслица абсолютная. Присоединяюсь к мнению тех, кто считает, что демонстрационные задачи должны быть интересными и жизненными.
Вроде всё правильно, но бессмыслица абсолютная. Присоединяюсь к мнению тех, кто считает, что демонстрационные задачи должны быть интересными и жизненными.
0
>а вот интересно, можно ли сделать compile-time рендеринг мандельброта на шаблонах C++?
мне было интересно www.gamedev.ru/flame/forum/?id=90646&page=2#m25
мне было интересно www.gamedev.ru/flame/forum/?id=90646&page=2#m25
+1
Меня в свое время очень сильно впечатлило использование шаблонной магии применительно к микроконтроллерам для абстрагирования драйвера внешнего устройства от пинов, к которым оно подключено.
easyelectronics.ru/rabota-s-portami-vvoda-vyvoda-mikrokontrollerov-na-si.html
easyelectronics.ru/rabota-s-portami-vvoda-vyvoda-mikrokontrollerov-na-si.html
+1
Где же я видел эту идею? А, вот тут: Printing 1 to 1000 without loop or conditionals
0
В следующем стандарте будет интереснее (попробовать можно уже сейчас: gcc.gnu.org):
Или даже ещё лучше:
constexpr int fact(int n)
{
if (n > 0)
return fact(n - 1);
else
return 1;
}
double array[fact(5)];
Или даже ещё лучше:
struct CompileTimeMap {
size_t hash;
const char* val;
} ctmap[] = { hash("123"), "123" };
Плюс обобщить макросом вида "#define CTH(str) hash(str), str".
+1
В § 7.1.5 п. 3 говорится, что в теле constexpr функции может быть только один return и никаких if.
Т.е. хотя бы так:
Т.е. хотя бы так:
constexpr int fact(int n) { return n > 0 ? fact(n - 1) : 1; }
+1
Sign up to leave a comment.
Магия шаблонов или вычисление факториала на стадии компиляции