для косвенно-рекурсивных функций. Если проблема форвард-объявлений для рекурсивных структур решается пусть не автоматически но более удобно через struct/class-префикс у полей то как теперь решить проблему необходимости вручную писать предварительные объявления для косвенно-рекурсивных функций?
auto func(auto n){
if (n == 1) return 1;
return n * func2(n - 1);
};
auto func2(auto n){
if (n == 1) return 1;
return n + func(n - 1);
};
>>clang: call to function 'func2' that is neither visible in the template definition nor found by argument-dependent lookup
Ведь это дико неудобно вручную писать сигнатуру функции, почему компилятор не может автоматически вставить объявление функции если не находит ее имя (и потом в конце парсинга TU поверяем была ли она объявлена и если нет то выдаем ошибку) ?
auto func2(auto arg); // why ???
auto func(auto n){
if (n == 1) return 1;
return n * func2(n - 1);
};
auto func2(auto n){
if (n == 1) return 1;
return n + func(n - 1);
};
Потому что наследие Си однопроходное
если ниже написать перегрузку то ваш код внезапно изменит поведение, то есть инклуд подключаешь непонятно где и меняется код выше, вы этогохотите?
Автоматическая генерация предварительных объявлений для неизвестных функций не влияет на однопроходность - я же говорю что компилятор по ходу парсинга может вставлять временные объявления для неизвестных функций и потом в конце парсинга TU посмотреть были эти функции объявлены и если нет то выдать ошибку. Однопроходность по прежнему сохраняется
Усложить жизнь всем ради непонятно чего
Ну вообще это не только про "усложнить жизнь" Часто вижу, что код на сях/плюсах пишут снизу вверх, потому как лень дублировать сигнатуру каждой функции. А я вот почему-то привык сверху вниз читать
>> почему компилятор не может автоматически вставить объявление функции если не находит ее имя Потому что это error-prone подход
Почему, ошибка-то при отсутствии определения ровно такая же будет
>> временные объявления для неизвестных функций С какой сигнатурой?
Опечатались одной буквой в имени существующей функции и получили ошибку на этапе линковки? Красиво...
Не линковки, конечно
auto name (auto arg1, auto arg2, ...) где число параметров будет равно числу аргументов при вызове неизвестной функции
А ничего, что auto name(auto arg); является декларацией совершенно другой перегрузки, нежели ожидает пользователь?
А какую декларацию вы вставите для такого вызова? foo(1, 2, {3, 4, 5}, 42);
Это же только временно при парсинге TU пока не встретится определение самой функции, как только встретилось то это временное объявление удаляем. Как оно может повлиять на какие-либо перезагрузки если это временное объявление учавствовать в перезагрузках не будет?
Это не так должно работать Первым проходом собираются все объявления и определения функций, на втором проходе обычный name lookup. Проблема в том, что это опять ломающее изменение, и в плюсах не появится.
>> пока не встретится определение самой функции, Как понять, что определение пользовательской функции совпадает со сгенерированной?
и такой подход реально ухудшит ситуацию с перегрузками
void f(double) {} void g(int i) { f(i); } void f(int) {} Предлагаю подумать над этим примером
С чем вы спорите-то?) Я вроде явно написал, что в C++ мы этой фичи не увидим, по крайней мере, до механизма вроде эпох.
вопрос не в том увидим или нет, а в том заачееем
А теперь представьте, что пользователь хотел, но забыл объявить f от double. Теперь вместо заблаговременной ошибки, он получит неожиданное поведение. Почти наверняка рантайм баг
Ну да, компилятор выберет функцию которая объявлена ниже потому что в файле больше нет никакого упомнания о другой перезагрузки функции (соотвественно никакие правила overloading и name-lookup нарушаться не будут) Аргумент "хотел но забыл" мне непонятен - если не объявить f(double) то компилятор сейчас выдает ошибку и логичнее было бы выбрать функцию которая объявлена ниже чтобы получить работающий код потому что сейчас согласно философии С++ считает что программист пишет код без ошибок и поэтому компиляторы вместо того чтобы проверять код на UB (и только потом уже оптимизировать) сразу бегут оптимизировать считая что UB нет что может приводить к удивительным багам (https://t.me/ProCxx/504005)
Вот именно. Сейчас будет ошибка, а вы предлагаете замести мусор под ковер
>> то компилятор сейчас выдает Именно, это ожидаемое поведение. А если не выдать ошибку, а вместо этого начать выбирать среди двух перегрузок ниже – пользователь не этого ожидал Кроме того, забытые инклуды начнут генерировать ещё более весёлые баги со сборкой проекта >> согласно философии С++ считает что программист пишет код без ошибок Боюсь, философия несколько сложнее и вы неверно её поняли. UB перекладывает ответственность на программиста... с благородной целью – обеспечить возможности оптимизации. Вы же предлагаете ради сиюминутного синтаксического сахара повысить риск отстрела ног, а так же затруднить непродуманной идеей будущее развитие языка Может, вам стоит написать собственный язык, чтобы понять процесс дизайна?
Я предлагаю не накидывать на программиста тупую работу которую может сделать компилятор, необходимость вручную предварительно объявлять сигнатуру функции (когда она же объявляется чуть ниже в этом же файле) это чистой воды болерплейт который не несет никакой информации и только раздувает код
А вы пробовали Rust? С таким бэкграундом и запросами явно лучше пойдет, без шуток.
Прочитайте внимательно то мое сообщение, я там по шагам описал алгоритм работы компилятора что код оказывается можно сначала проверить на ошибки (и избежать того бага в статье) и только потом начать его оптимизировать. Это совершенно никак не уменьшает возможности по оптимизации кода в случае UB. Но компиляторы не хотят этого делать считая что разработчик сразу пишет код без ошибок
сигнатуры функций и объявления классов - отличная фича С/С++, существенно облегчающая навигацию по коду, его понимание, и в целом поддерживаемость
Вы же понимаете, что комитет наоборот предпринимал меры, минимизирующие влияние последующего кода?
кхе-кхе концепты кхе-кхе
Вот сюда ещё дописать слово inline в объявления inline void f(double) {} inline void g(int i) { f(i); } void f(int) {}
Теперь нарушен ODR, никакие/некоторые TU после линковки несут ошибочный код, удачной отладки
Я пробовал разные языки за 9 лет разработки. Я даже несколько месяцев в фулл-тайм режиме писал свой язык и я конечно хотел бы писать на нем но это потом когда я перестану искать работу по найму и смогу заниматься своими стартапами. А пока мне нужен популярный язык (чтобы на нем можно было бы найти работу) и к плюсам я сейчас пришел сознательно (после 7 лет JS/TS веб-разработки) потому что 1) С/С++ это один из самых популярных языков и развитых экосистем и уступает разве что только JS по количеству вакансий (и тот же Rust здесь в подметки не годится) 2) С++ мне нравится тем что это очень гибкий язык по сути конструктор из которого я могу слепить язык под свои вкусы чтобы писать на плюсах код так как я привык на другом языке (или точнее с теми же удобствами). Раст в этом плане намного менее гибкий и там много чего форсируется
Обсуждают сегодня