- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 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
}
но нет
Когда компилятор увидит get, он сначала будет искать функции, а потом, если не найдёт, будет искать подходящих френдов.
2. Но у нас нет обычных функций (и даже обычных френдов), у нас только шаблоны.
3. Из шаблонов компилятор должен сгенерировать конкретные реализации для каждого типа. Это не жабьи генерики и не язык с динамической типизацией, решение должно быть принято на этапе компиляции.
4. В блоке, который never called, создаётся одна из конкретных реализаций шаблона. Она помещается в объектный файл в секцию кода, её видит линкер.
5. О, чудо! Замангленное имя той фигни, которая создалась в блоке "never called" (а именно френд get класса set<type<tag>, decltype(call)>{}), наиболее близко подходит под сигнатуру требуемой функции.
Ну просто писать простой предсказуемый код на С++ и течь?
Или обязательно нужно пройти все круги ада выбора перегруженной функции и остановиться на случайной лямбде?
Перегрузки в С++ адские конено, я бы старался из избегать без необходимости
причем там есть И перегрузки И дефалтные значения (как в котлине)) , это наверное опасно если скрестить их с шаблонами
перегрузки + шаблоны = пздц
Главным героем фильма является Данила Багров — молодой человек неопределённого рода занятий и без определённого места жительства. Герой вырос в неполной семье в бедном и безымянном захолустье — многие посмотревшие фильм ассоциировали героя Бодрова с собой и хотели быть на него похожим — хотели строить так сказать свою жизнь по тем же клише. Важная деталь — в прошлом герой служил и воевал, однако не страдает никаким ПТСР, наоборот — служба в армии и война помогла стать ему настоящим мужчиной и научила чётко и ровно решать вопросы.
Враги главного героя — всякие коммерсы, которые занимаются непонятно чем, но главный враг Данилы — живёт за океаном и появляется только во втором фильме. Это — пиндосы. Именно заокеанские пиндосы являются средоточием мирового зла и проецируют все проблемы для Родины Данилы — к примеру, занимаются обманом наших спортсменов, а когда этот обман вскрывается — убивают их. Ещё пиндосы занимаются наркотрафиком, съёмками порнографии и угнетают негров.
Причем конюх это лямбда, объявленная вообще внутри
В сухую, безветренную погоду можно увидеть и самого Боярского
обознался
если это автоматическая переменная, то там мусор (а если например глобальная то ноль).
Мусор это точно UB. Ноль -- хз, вероятнее всего экспешен как и попытка разыменовать нуль
(дисклаёмер: я не плюбсоеб)
То ли дело первый писюк на 4 MHz.
Си пришли в районе 386, он уже был ближе к 20.
386 уже были и на 33, и на 40. Кажется, 40 было пределом, быстрее были только 486.
большинство софта года до 1987-го под PC писалось на асме
Кернигана и Ритчи я могу понять: они сидели за старым компом и выживали, как могли. Но зачем Страуструп сохранил все эти концепции (разве что сделал прототипы обязательными и отменил "автовывод" в int)?
И уж совсем чудовищным на этом фоне кажется boost: компилятор, экономящий на инициализации данных и на проверках границ массивов и сношающий конюха за неимением горничной, и в то же время библиотека необъятного размера, компилирующаяся за непредсказуемое время.
Примерно всё вокруг него было написано на сях (и чуть чуть на фортране).
Примерно все вокруг него умели писать на си.
Если бы он сделал язык, не совместимый с си, его бы не поняли.
Boost, вероятно, думает что лучше 3 часа компилироваться, а потом экономить 3 секунды работы. В каком-то смысле их можно понять
Ну вот представь ты пришел в контору, где все (не дай бог) на JavaScript. Миллионы строк кода и пара сотен программистов на JS.
И ты пишешь новый язык. Что ты возьмешь за основу?
фейсбук и вконтакт именно так и сделали
и именно потому что овердохуя кода
Как и первая версия крестоговняного "компилятора" 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