- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
https://habr.com/ru/article/448466/
*/
А последние пару лет набирает популярность boost.hana. Это boost.fusion,
но с constexpr'ом и лямбдами. Автор hana, Луис Дионе (Louis Dionne),
используя на полную мощь все возможности новых стандартов, в некотором
смысле очеловечил метапрограммирование. С помощью hana всяческие
манипуляции с типами, их кортежами, отображениями, а также компайл- и
рантайм-работа с ними обрели практически человеческое лицо и читаемый
вид. Ну, с поправкой на синтаксис C++, разумеется. Вот, например, как выглядит
универсальный сериализатор структур, написанный с помощью hana:
*/
// 1. Give introspection capabilities to 'Person'
struct Person {
BOOST_HANA_DEFINE_STRUCT(Person,
(std::string, name),
(int, age)
);
};
// 2. Write a generic serializer (bear with std::ostream for the example)
auto serialize = [](std::ostream& os, auto const& object) {
hana::for_each(hana::members(object), [&](auto member) {
os << member << std::endl;
});
};
// 3. Use it
Person john{"John", 30};
serialize(std::cout, john);
/*
Ну да, структуры приходится описывать особым образом. А кому сейчас легко?
И тут хочется также отметить библиотеку tinyrefl за авторством Manu Sánchez
(Мануэля Санчеса). Довольно неплохая попытка принести в мир C++-разработки
статическую рефлексию без расширения компилятора. Для своей работы библиотека
требует стороннюю утилиту (cppast), но зато предоставляет довольно удобный доступ
к информации о структурах, которую можно использовать в процессе разработки
программы. Преимущество этой библиотеки (по сравнению с другими) в том, что для
работы с ней не надо использовать «птичий язык», а элементы структур (как и сами
структуры) можно произвольным образом атрибутировать прямо в исходном коде:
*/
struct [[serializable]] Person {
std::string name;
int age;
};
template<typename Class>
auto serialize(std::ostream& os, Class&& object) -> std::enable_if_t<
tinyrefl::has_metadata<std::decay_t<Class>>() &&
tinyrefl::has_attribute<std::decay_t<Class>>("interesting"),
std::ostream&>
{
tinyrefl::visit_member_variables(object, [&os](const auto& /* name */, const auto& var) {
os << var << std::endl;
});
return equal;
}
/*
Таких примеров можно привести ещё много (или найти на гитхабе или гитлабе).
Объединяет все эти библиотеки и инструменты одна особенность: значительно
облегчая жизнь своим пользователям, они имеют такую реализацию, что остаётся
лишь предполагать, какое количество страданий испытали их разработчики. Достаточно
заглянуть в реализацию, увидеть забор из ifdef'ов и угловых скобок — и всё понятно.
Нередко эти реализации делаются на грани возможностей компиляторов. workaround'ы
банальных ошибок (или особенностей реализации языка конкретной версии конкретного
компилятора с конкретными флагами) здорово раздувают их код. Желание поддерживать
несколько стандартов сразу заставляет придумывать зубодробильные конструкции.
Безусловно, простая попытка реализовать что-нибудь подобное здорово поднимает уровень
владения языком (иногда — и самооценку). Но в какой-то момент, после многочасовой возни
с очередной ошибкой, или непроходящим тестом, или крэшем компилятора руки опускаются,
хочется плюнуть и бросить, ибо силы бороться иссякают.
*/
j123123 21.04.2019 03:07 # +1
> Но это, как говаривал Барон, ещё не все. Однажды в мир разработки C++ пришёл clang со своим фронтендом (а чуть позже — с libtooling), и мир изменился, заиграл новыми красками. Появилась надежда. Ибо появился инструмент, позволяющий относительно просто (относительно!) анализировать исходные тексты на C++ и что-нибудь с результатами этого анализа делать. Появились (и стали набирать популярность) утилиты типа clang tidy, clang format, clang static analyser и прочие. А некоторые разработчики приспособили clang frontend для решения задач рефлексии. Так, скажем, работают упомянутые выше cppast (за авторством Jonathan Müller) и tinyrefl на её базе. Так работает автопрограммист, используемый в нашей компании для кодогенерации (или его open-source-аналог).
> Разумеется, и до появления clang писались генераторы на основе исходного кода C++. Кто-то использовал для этого Python с самописными парсерами, кто-то разбирал C++ с помощью regexp'ов. Кто-то, как автор этой статьи, писал самопальный парсер на C++. Но, полагаю, с развитием инструментария это будет уходить в прошлое.
> Идея проста. Берётся исходный текст на C++ (например, объявления структур), пропускается через clang frontend, и на основе полученного AST генерируется новый исходный текст.
Именно поэтому.
j123123 21.04.2019 03:11 # +1
Я уже не один раз высказывал эту гениальную мысль на страницах говнокода
http://govnokod.ru/25397#comment460314
http://govnokod.ru/25407#comment461860
j123123 21.04.2019 03:16 # +2
> Currently the performance is really bad, there is a talk to make wasm based jit machine in a compiler to accelerate constexpr, but problem is keeping the undefined behavior-less behavior :)
бггг
j123123 21.04.2019 03:49 # +1
> We really need an allocation mechanism in constexpr. But I don't need to return the allocated object outside of a constexpr function...
> Is std::array constexpr? If so, can it decay to a ptr and be cast to any type at will?
> You can’t cast to any type in constexpr.
https://memepedia.ru/wp-content/uploads/2017/07/хохочущий-испанец.jpg
j123123 21.04.2019 03:52 # +1
> I really need C++ to be able generate goto-s and labels.
ох блядь... make me unsee it
j123123 21.04.2019 03:19 # +2
> Макросы (C++), шаблоны (C++98), свойства типов и constexpr'ы (C++11), концепты (C++20) — с каждым новым стандартом и витком развития язык предоставляет разработчику всё больше информации о том, что творится в недрах компилятора: начиная от манипуляции на уровне лексем и заканчивая compile-time-вычислениями и декларативным описанием свойств пользовательских типов. Логичное завершение (или продолжение?) этой цепочки — предоставление разработчику возможности напрямую манипулировать процессом компиляции кода на уровне AST. И такое предложение уже есть.
Ох б%?№^& сука... ну охуеть теперь. Лучше сделайте новый язык, а этот выкиньте нахуй. Сделайте диалект лиспа с байтоебством и без GC. Я довольно хуево себе представляю то, каким образом с текущим крестоговносинтаксисом вы буделе делать манипуляции с AST
bormand 21.04.2019 04:30 # +1
И с UB'ами во время конпеляции!
Но это уже будут не кресты. Вся суть крестов - прикручивать к ним новую хуйню не ломая совместимость со старой. Это как игра про башню из кирпичиков.
j123123 21.04.2019 21:57 # +1
Как строить башню из брикетов спрессованного дерьма. http://toplivnye-brikety.mya5.ru/toplivnye-brikety-iz-navoza/
Эту башню еще постоянно перекашивает под собственным весом, и стоит она на таком же самом фундаменте из говна. И даже если эту говноконструкцию идеально сбалансируют и стабилизируют - всё равно она останется говном и будет вонять
cmepmop 21.04.2019 22:30 # +1
PACTPOBblu_nemyx 22.04.2019 00:57 # +1
guest8 21.04.2019 22:42 # −999
guest8 21.04.2019 23:03 # −999
guest8 22.04.2019 00:45 # −999
guest8 22.04.2019 00:53 # −999
guest8 22.04.2019 02:38 # −999
guest8 22.04.2019 00:02 # −999
guest8 22.04.2019 00:47 # −999
bormand 21.04.2019 04:49 # +1
В предложении про метаклассы это выглядело довольно просто - из constexpr блока можно позвать оператор -> {...} который высрет хуйню из скобок в родительский блок и раскроет в ней $переменные. Ну и оператор $, которым можно получить constexpr инфу о типе.
Конечно как всегда с кучей ебанутых ограничений и костылей. Но они почти придумали лисповые макросы :)
bormand 21.04.2019 04:57 # +1
j123123 21.04.2019 16:44 # +1
Или я нихуя не понял, или это говно никакого (или почти никакого) отношения к лисповым макросам не имеет.
Вот представим себе некий гомоиконный язык, в котором нет циклов for но есть ite и goto. И допустим у нас будет функция, которая считает сумму чисел от 1 до 10
Ну и если захотим, можно впилить в язык цикл for, который будет трансформироваться в конструкцию с этим условием с goto и присвоением, типа вот:
и всё это достаточно легко будет делаться, мы просто рассматриваем нашу программу как связный список связных списков, больше нихуя нет, мы просто пишем код (макрос), который при вставке в код for вот с такими-то аргументами трансформируется/раскрывается вот в такой-то код, для этого "for" мы просто пишем код, который конструирует на основе аргументов какой-то новый код через связные списки связных списков и ... и все. Это - ПРОСТО.
Когда же я читаю про метаклассы то это вообще хуйня какая-то. Классы какие-то, зачем мне вообще классы? Вот представим на минуту, что из крестов выпилили нахер for(), while() циклы, но зато есть if() и goto label, через эти метаклассы можно запилить for()? Если нет, при чем тут тогда лисповые макросы?
j123123 21.04.2019 17:21 # +1
> A metaclass is written as a compile-time constexpr function that takes meta::type parameters, which are passed with reference semantics
...
> In the latter form, it can be used to use the values or abstract state of objects of meta::type.
...
> A pure base_class is a class that has no instance data, is not copyable, and whose a destructor is either public and virtual or protected and nonvirtual. Unlike an interface, it can have nonpublic and nonvirtual functions.
...
блядь, сколько хуйни на ровном месте. Какие-то pure base_class, какие-то методы, классы, хуяссы, констэкспры, meta::type. ЗАЧЕМ? ЗАЧЕМ ЭТО ВСЁ? Как это соотносится с лисповыми макросами?
bormand 21.04.2019 19:07 # +1
З.Ы. Я одну из первых версий пропозала читал, возможно сейчас там всё поменялось.
j123123 24.04.2019 01:24 # +1
j123123 24.04.2019 01:28 # +1
guest8 24.04.2019 02:02 # −999
j123123 24.04.2019 08:04 # +1
BOKCEJIbHblu_nemyx 21.04.2019 18:20 # +1
ahead —– отмечает безусловный переход вперёд;
if —– отмечает условный переход вперёд;
then —– разрешает переход вперёд;
begin —– отмечает переход назад;
until —– разрешает условный переход назад;
again —– разрешает безусловный переход назад;
cs-pick и cs-roll для работы со стеком потока управления.
Всё остальное можно реализовать поверх них:https://ideone.com/00PGzJ
bormand 21.04.2019 04:04 # +1
> требует стороннюю утилиту
Мне одному кажется, что это и есть расширение конпелятора?
j123123 21.04.2019 04:09 # +1
bormand 21.04.2019 04:11 # +1
j123123 21.04.2019 04:15 # +2
guest8 21.04.2019 04:11 # −999
unicorn 22.06.2019 15:06 # +1
PA3yMHblu_nemyx 22.06.2019 15:21 # +2
guest8 21.04.2019 04:14 # −999
guest8 21.04.2019 04:21 # −999
BOKCEJIbHblu_nemyx 21.04.2019 07:18 # +3
Божечки, почему программисты стабильно изобретают колесо и текут от этого?
Xyu_HE_3HAET 21.04.2019 07:51 # +1
BOKCEJIbHblu_nemyx 21.04.2019 09:22 # +1
Xyu_HE_3HAET 21.04.2019 10:53 # +1
OCETuHCKuu_nemyx 21.04.2019 11:54 # +1
Xyu_HE_3HAET 21.04.2019 12:11 # +1
BOKCEJIbHblu_nemyx 21.04.2019 12:52 # +1
Xyu_HE_3HAET 21.04.2019 12:56 # +1
return (n==0) ? acc : fac_times(n - 1, acc * n);
}
int factorial (int n) {
return fac_times (n, 1);
}
BOKCEJIbHblu_nemyx 21.04.2019 13:10 # +3
Xyu_HE_3HAET 21.04.2019 12:57 # +1
guest8 21.04.2019 13:20 # −999
CHayT 24.04.2019 16:18 # +1
Тут проблема не в отсутствии гомоиконности, а в том, что только полному отморозку придёт в голову использовать в качестве схемы данных крестомакросню:
– Как нам распарсить этот бинарный блоб, г-н Рахитектов?
– Для начала чекаутни ревизию fd3fgsf4 нашего проекта и грепни на 'BOOST_HANA_DEFINE_STRUCT(Sosnoolee'
Надо чтобы ASN.1!
CHayT 24.04.2019 16:22 # +1
guest8 22.06.2019 00:20 # −999