- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
#include <cstdio>
class tag;
template<class>
struct type { friend constexpr auto get(type); };
template<class TKey, class TValue>
struct set { friend constexpr auto get(TKey) { return TValue{}; } };
void foo() { // never called
if constexpr(false) { // never true
if (false) { // never true
constexpr auto call = [](auto value) { std::printf("called %d", value); };
void(set<type<tag>, decltype(call)>{});
}
}
}
int main() {
get(type<tag>{})(42); // prints called 42
}
но нет
Главным героем фильма является Данила Багров — молодой человек неопределённого рода занятий и без определённого места жительства. Герой вырос в неполной семье в бедном и безымянном захолустье — многие посмотревшие фильм ассоциировали героя Бодрова с собой и хотели быть на него похожим — хотели строить так сказать свою жизнь по тем же клише. Важная деталь — в прошлом герой служил и воевал, однако не страдает никаким ПТСР, наоборот — служба в армии и война помогла стать ему настоящим мужчиной и научила чётко и ровно решать вопросы.
Враги главного героя — всякие коммерсы, которые занимаются непонятно чем, но главный враг Данилы — живёт за океаном и появляется только во втором фильме. Это — пиндосы. Именно заокеанские пиндосы являются средоточием мирового зла и проецируют все проблемы для Родины Данилы — к примеру, занимаются обманом наших спортсменов, а когда этот обман вскрывается — убивают их. Ещё пиндосы занимаются наркотрафиком, съёмками порнографии и угнетают негров.
Как и первая версия крестоговняного "компилятора" Cfront, которая по сути являлась говнопрепроцессором поверх сишки. А первые версии сишкокомпиляторов были кривыми говнотрансляторами в ассемблер PDP-11
У жабы нет генериков в компайл тайме ради совместимости с говном 1998 года, например
До скорой встречи!
Перфоманс
https://gcc.godbolt.org/z/U-fv8o
1. Тело функции foo состоит из nop, поскольку там if constexpr(false).
2. Но эта пустая функция на этапе компиляции создаёт специализацию шаблона set<type<tag>, decltype(call)>.
3. Её френд по имени get (в ассемблерном выхлопе метка _ZZ3foovENKUlT_E_clIiEEDaS_) возвращает экземпляр класса, переданного во втором аргументе (т. е. создаёт экземпляр decltype(call)).
4. В свою очередь decltype(call){}() в C++20 приводит к вызову лямбды (только без захвата контекста; замыкания через конструктор вызвать не получится).
Осталось понять, почему вызвана функция _ZZ3foovENKUlT_E_clIiEEDaS_, она же set<type<tag>, decltype(call)>::get(type<tag>), чья специализация родилась в недрах foo. Тропинка к ней от вызова get(type<tag>{})(42) в main появилась благодаря SFINAE: это функция, максимально подходящая под сигнатуру get(type<tag>).
Перед лямбдой, кстати, вызывается конструктор type<tag>{}, и он пустой.
class tag же нужен для того, чтобы объявление get(type<tag>) было т.н. "templated entity" ([temp.pre]/8) — иняче определение get() из set<> ня сматчится с объявлением.
Хотя всё равно непонятно, какого чёрта он пытается использовать эту лямбду внутри foo.
Переписал без лямбды:
https://ideone.com/CKQgWG
Всё равно лезет в блок, который внутри if (false), который внутри if constexpr(false), который внутри void foo(), которая никогда не вызывается.
https://cppinsights.io/s/e5c7acb2
Но в компиляторах до C++20 выкинет с сообщением об ошибке:
Конструктор с атрибутом deleted перекрыть не получается. Либо это невозможно, либо я слишком анскилльный.
Заменил вызов конструктора вызовом статического метода. Компилируется в C++17 (если бы не if constexpr, можно было бы ещё понизить версию стандарта).
https://cppinsights.io/s/6a95dc50
Ну и вот еще https://habr.com/ru/post/268141/ https://stackoverflow.com/questions/44267673/is-stateful-metaprogramming-ill-formed-yet