Тут недавно холиварчик был С vs С++, там как одно из преимуществ С была запись
struct T { int a, b; };
T t = {.a = 1, .b=42};
Если с таким разбирается компилятор С, то что мешает компилятору С++ разобраться с
void f(int a, int b);
f(.a = 1, .b=42);
Понятно, что в некоторых редких случаях в разных единицах трансляции названия аргументов f могут быть разными (или вообще отсутствовать). Но если аргументы разные и используется такой вызов, то это можно просто трактовать как нарушение ODR (очередное недиагностируемое ).
Понятно, что есть буст, но имхо, то, что там предлагается, выглядит уродливо, порождает нечитаемые сообщения об ошибках, засоряет пространство имен (или на ровном месте вводит новое), замедляет компиляцию, подозреваю также, у него есть проблемы с перегрузкой и неявными преобразованиями. Кроме того, оно требует правки хидеров или написания врапперов. Такие вещи все ж должны быть на уровне языка.
Ваше мнение?
Re: А почему нет вызова функций с именованными аргументами?
Здравствуйте, enji, Вы писали:
E>Если с таким разбирается компилятор С, то что мешает компилятору С++ разобраться с E>
E>void f(int a, int b);
E>f(.a = 1, .b=42);
E>
... E>Ваше мнение?
Мое скромное мнение — это синтаксический оверхед Для 2-4 аргументов можно запомнить, что из них какой означает. Если аргументов больше, значит нужно менять функцию (вносить в класс, разбивать на несколько, передавать в конце концов структуру с параметрами). И да, функции Win32 API — это неизлечимая клиника.
Re: А почему нет вызова функций с именованными аргументами?
Здравствуйте, enji, Вы писали:
E>что мешает компилятору С++ разобраться с E>
E>void f(int a, int b);
E>f(.a = 1, .b=42);
E>
E>Понятно, что в некоторых редких случаях в разных единицах трансляции названия аргументов f могут быть разными (или вообще отсутствовать). Но если аргументы разные и используется такой вызов, то это можно просто трактовать как нарушение ODR (очередное недиагностируемое ).
это сломает обратную совместимость.
In Zen We Trust
Re[2]: А почему нет вызова функций с именованными аргументами?
Здравствуйте, PM, Вы писали:
PM>Мое скромное мнение — это синтаксический оверхед
В синтаксическом оверхеде нет ничего плохого, если он упрощает жизнь +=, ++, лямбды — все это синтаксический оверхед...
PM>Для 2-4 аргументов можно запомнить, что из них какой означает.
да как сказать. Вот к примеру я стараюсь не использовать булевых аргументов
void addElement(T, bool replace);
enum ReplaceOrNot {
Replace, DontReplace
};
void addElement2(T, ReplaceOrNot replace);
addElement(1, false);
addElement2(1, Replace);
addElement(1, .replace=true); // также понятно, как и addElement2, но нет оверхеда с созданием enum
// да, можно сделать два метода - addElement(T), addOrReplaceElement(T) - но если булевых аргументов два - то делать четыре?
// да, можно аргументы метода передавать в виде структуры. Можно даже изобрести объект-метод addElement(1).replace(false)()
// но все это обход недостатка языка...
И опять же, пока я работаю над каким-то кодом, я помню. Но когда через год приходится в нем снова ковыряться, то я уже не помню
Re: А почему нет вызова функций с именованными аргументами?
Здравствуйте, PM, Вы писали:
PM>Мое скромное мнение — это синтаксический оверхед Для 2-4 аргументов можно запомнить, что из них какой означает. Если аргументов больше, значит нужно менять функцию (вносить в класс, разбивать на несколько, передавать в конце концов структуру с параметрами). И да, функции Win32 API — это неизлечимая клиника.
Ну это лично ваше мнение, я считаю наоборот, что не надо использовать лишний раз структуры и классы, если для этого нет предпосылок. Win API вполне себе нормальное API (если не считать анахронизмов), а такие библиотеки как boost — вот это вот клиника.
Re: А почему нет вызова функций с именованными аргументами?
Язык C++ кривой, а его все развивают, да еще и с сохранением дурацкой "обратной совместимости". Если перечислять чего в нем нету то можно составить список из сотен пунктов.
Идея хорошая, я к ней пришел независимо и достаточно давно, но ввиду огромного количества древних костылей типа системы инклудов и прочего вряд ли это можно сделать.
Re: А почему нет вызова функций с именованными аргументами?
Наше мнение — надо двигаться от усложнизма к упростизму(простигосподи), всё гениальное просто(с), вызов функции вида "f(.a = 1, .b=42)" эээ, явный перебор
Re: А почему нет вызова функций с именованными аргументами?
Задачка Саттера "какая функция вызовется" (с шаблонными функциями, специализациями, не-шаблонными перегрузками, дефолтными параметрами) могла бы выйти на новый уровень сложности.
Русский военный корабль идёт ко дну!
Re: А почему нет вызова функций с именованными аргументами?
Здравствуйте, enji, Вы писали:
E>Здравствуйте, Abyx, Вы писали:
A>>это сломает обратную совместимость.
E>гм. Это каким же образом?
ну возможно я погорячился насчет "обратной совместимости",
но тем не менее твоя идея требует чтобы имена параметров были одинаковые в пределах единицы трансляции.
а в тоннах легаси кода это не так.
In Zen We Trust
Re: А почему нет вызова функций с именованными аргументами?
Их регулярно заворачивают взад обратно. Первым их кажется завернул лично Страуструп из C++98 proposal, так с тех пор и повелось.
В языке и без того можно найти способ
(кстати автор по моей ссылке неявно цитирует метод, также предложенный ещё Страуструпом, но мне лень искать оригинальный)
Мне кажется, это harmful, хотя бы потому, что заставляет меня иметь имена параметров как часть сигнатуры функции. Отвратительно. В сигнатуру должны входить только типы, имена должны быть up-to-me. Захотел и переименовал, не разрушив существующего кода.
Для меня более забавно, что традиционно более консервативный комитет по стандартизации C пропустил инициализацию структур в таком виде.
Re[2]: А почему нет вызова функций с именованными аргументами?
Здравствуйте, Tilir, Вы писали:
T>Мне кажется, это harmful, хотя бы потому, что заставляет меня иметь имена параметров как часть сигнатуры функции. Отвратительно. В сигнатуру должны входить только типы, имена должны быть up-to-me. Захотел и переименовал, не разрушив существующего кода.
соглашусь. у функций может быть много объявлений и одно определение. необходимость протаскивать одинаковые имена для параметров во всех объявлениях сильно напряжет и сломает обратную совместимость. по сути имена параметров станет частью сигнатуры. со структурами такой проблему нет: при определении структуры надо прописать один раз имена свойствам
Re[3]: А почему нет вызова функций с именованными аргументами?
Здравствуйте, DiZSl, Вы писали:
DZS>Ну это лично ваше мнение, я считаю наоборот, что не надо использовать лишний раз структуры и классы, если для этого нет предпосылок. Win API вполне себе нормальное API (если не считать анахронизмов), а такие библиотеки как boost — вот это вот клиника.
Мне лень искать в WinAPI функцию кажется с 19-ю аргументами (емнип где-то в подсистеме безопасности), но вот всем известные CreateWindow и RegisterClass:
HWND WINAPI CreateWindow(
_In_opt_ LPCTSTR lpClassName,
_In_opt_ LPCTSTR lpWindowName,
_In_ DWORD dwStyle,
_In_ int x,
_In_ int y,
_In_ int nWidth,
_In_ int nHeight,
_In_opt_ HWND hWndParent,
_In_opt_ HMENU hMenu,
_In_opt_ HINSTANCE hInstance,
_In_opt_ LPVOID lpParam
);
Не знаю, чем руководствовались разработчики (может быть это были 2 разных команды), но я не вижу преимуществ в способе задания параметров для CreateWindow перед RegisterClass.
Про boost в моем сообщении ничего не было, так что оставлю без комментариев.
Re[4]: А почему нет вызова функций с именованными аргументами?
Здравствуйте, Abyx, Вы писали:
A>ну возможно я погорячился насчет "обратной совместимости", A>но тем не менее твоя идея требует чтобы имена параметров были одинаковые в пределах единицы трансляции. A>а в тоннах легаси кода это не так.
Ну прям вот так уж и в тоннах? Разные имена параметров означают, что одна и таже функция определена по разному в двух разных хидерах. Насколько это частое явление?
Да даже если в какой-то либе оно частое — просто компилятор будет ругаться при попытке вызвать ее таким образом...
Или не будет, если это разные единицы трансляции И у нас будет еще одно не диагностируемое нарушение ODR
Собственно сейчас же как то живут с таким
/// a.cppstruct T {
std::string s;
} a;
/// b.cppstruct T {
int q;
std::string s;
} b;
Re[2]: А почему нет вызова функций с именованными аргументами?
AG>Задачка Саттера "какая функция вызовется" (с шаблонными функциями, специализациями, не-шаблонными перегрузками, дефолтными параметрами) могла бы выйти на новый уровень сложности.
ну есть такое дело. И что? Да, будут какие-то новые темные углы. И можно будет прострелить себе ногу новым способом. Но в плюсах уже есть сотни таких способов, что добавит еще один?
Для начала его можно оградить, запретив такой вызов там, где с ним вероятны проблемы...
Re[2]: А почему нет вызова функций с именованными аргументам
Здравствуйте, Tilir, Вы писали:
T>В языке и без того можно найти способ T>(кстати автор по моей ссылке неявно цитирует метод, также предложенный ещё Страуструпом, но мне лень искать оригинальный)
Дык и лямбды не нужны, можно же найти способ
Про описанный способ я в курсе. И если бы имелся нормальный макропроцессор (который мог бы на основе функции сделать такой класс) — он бы вполне устроил. Но сейчас это все надо писать руками или городить что-то на BOOST_PREPROCESSOR — а это сильно захламляет объявление...
T>Мне кажется, это harmful, хотя бы потому, что заставляет меня иметь имена параметров как часть сигнатуры функции. Отвратительно. В сигнатуру должны входить только типы, имена должны быть up-to-me. Захотел и переименовал, не разрушив существующего кода.
А чем функция принципиально отличается от структуры/класса в этом смысле ? Если код твой — отрефакторил, если чужой — ну что ж, придется с этим жить.
Опять же, взять тот же питон, вба, скалу (вроде бы) — там это есть, и ничего, полет нормальный...
T>Для меня более забавно, что традиционно более консервативный комитет по стандартизации C пропустил инициализацию структур в таком виде.
Здравствуйте, enji, Вы писали:
PM>>Для 2-4 аргументов можно запомнить, что из них какой означает. E>да как сказать. Вот к примеру я стараюсь не использовать булевых аргументов
<здесь был код>
Рекомендацию про неиспользование булевых параметров встречал только от пишущих на Java, сам проблем с ними не испытываю
Наверно дело вкуса, для меня вариант с addElement(T), addOrReplaceElement(T) вполне приемлем. Меня больше настораживает странная структура данных которая позволяет добавлять и уникальные элементы, и дубликаты.
E>И опять же, пока я работаю над каким-то кодом, я помню. Но когда через год приходится в нем снова ковыряться, то я уже не помню
Думаю тут дело не только в коде, через год придется всё равно что-то вспоминать. Вот прямо сейчас я залез в свой же код годовалой давности, вспоминаю
Re[3]: А почему нет вызова функций с именованными аргументами?
Здравствуйте, uzhas, Вы писали:
U>соглашусь. у функций может быть много объявлений и одно определение. необходимость протаскивать одинаковые имена для параметров во всех объявлениях сильно напряжет и сломает обратную совместимость. по сути имена параметров станет частью сигнатуры. со структурами такой проблему нет: при определении структуры надо прописать один раз имена свойствам
Почему это у функции много объявлений? Функция объявляется в хидере, дальше хидер подключается куда надо. Если у тебя это не так — то почему тебя не напрягает требование ODR для структур?
И это второй коммент про обратную совместимость, абикс писал уже. Каким боком это нововведение ее сломает?
Re: А почему нет вызова функций с именованными аргументами?
Здравствуйте, enji, Вы писали:
E>Тут недавно холиварчик был С vs С++, там как одно из преимуществ С была запись E>
E>struct T { int a, b; };
E>T t = {.a = 1, .b=42};
E>
E>Если с таким разбирается компилятор С, то что мешает компилятору С++ разобраться с E>
E>void f(int a, int b);
E>f(.a = 1, .b=42);
E>
E>Ваше мнение?
Смешались кони, люди. Почему вы спрашиваете про именованные аргументы и в с++ приводите пример функции?
В си у вас инициализируется структура, а в с++ у вас параметризованная функция.
Например в с мы имеем здоровую структуру, а мы там частенько иемеем здоровую структуру, так что же нам делать если не все поля структуры нам нужно указать без этой фичи?
Правильно, ничего. Ничего кроме нудного указывания всех полей, подряд.
Не знаю насчет аргументов метода, но по мне в некоторых случаях читаемость улучшается. А это нынче важно, очень.
Так что мое мнение, любая фича языка, которая улучшает читабельность кода, должна присутствовать. Конечно можно сувать это куда попало, но все же полезно было бы иметь.
Re[4]: А почему нет вызова функций с именованными аргументами?
Здравствуйте, enji, Вы писали:
E>Если с таким разбирается компилятор С, то что мешает компилятору С++ разобраться с E>
E>void f(int a, int b);
E>f(.a = 1, .b=42);
E>
E>Ваше мнение?
Моё мнение такое: экономит надо не время записи, а время чтения.
Запись: E>f(.a = 1, .b=42);
ничем не лучше, а даже хуже, чем:
const int a = 1;
const int b = 42;
f(a, b);
Но, что такое a? Что такое b? —
Вызов функции с константами определёнными по месту вызова — это экзотика для хорошего стиля.
Если в программе встречается более чем один вызов функции с одинаковыми не именованными константами, то это уже плохо. Следует либо поименовать константы, либо завернуть вызов функции в другую функцию, например:
inline void LastAnswerOnUltimateQuestion()
{
const int nAnswerNumber = 1;
const int nAnswerValue = 1;
f(nAnswerNumber, nAnswerValue);
}
Заметили ошибку? Легко исправить?
А вы бы её заметили, во всех разбросанных по коду вызовах:
// file: start.cpp
f(.nAnswerNumber = 1, .nAnswerValue = 42);
// file: background.cpp
f(.nAnswerNumber = 1, .nAnswerValue = 42);
// file: crash.cpp
f(.nAnswerNumber = 1, .nAnswerValue = 1);
?
Легко исправить?
Здравствуйте, Tilir, Вы писали:
T>Отвратительно. В сигнатуру должны входить только типы, имена должны быть up-to-me. Захотел и переименовал, не разрушив существующего кода.
Кстати, а почему? Функцию ведь вы не переименуете, не разрушив существующего кода. Имя функции "более стабильно", чем имя параметра? Ой, не уверен...
Re[5]: А почему нет вызова функций с именованными аргументами?
Здравствуйте, enji, Вы писали:
E>Здравствуйте, Abyx, Вы писали:
A>>ну возможно я погорячился насчет "обратной совместимости", A>>но тем не менее твоя идея требует чтобы имена параметров были одинаковые в пределах единицы трансляции. A>>а в тоннах легаси кода это не так.
E>Ну прям вот так уж и в тоннах? Разные имена параметров означают, что одна и таже функция определена по разному в двух разных хидерах. Насколько это частое явление?
Очень частое:
// foo.hvoid foo(int a, int b);
//foo.cppvoid foo( int/* a */, int/* b */ )
{
// а и b не используются, поэтому, в определении их закоментировали, чтобы избежать предупреждения компилятора.
}
Re[3]: А почему нет вызова функций с именованными аргументам
Здравствуйте, enji, Вы писали:
E>Дык и лямбды не нужны, можно же найти способ
Разумеется, лямбды не нужны.
Но в комитете по стандартизации тоже люди, лямбды позволяют писать однострочники-функторы для всяких STL-алгоритмов, писать на каждый чих классы-функторы действительно всех задолбало, и в конце концов лямбды это модно, поэтому они в стандарте. А именованные аргументы функций это скучно, никому ни для чего внятного не нужно, вызывает ассоциации с VBA и хоронит надежды на плюсовый ABI. Они и раньше-то были невелики "экспортировать класс из shared object" почти в точности означает "убить себя об стену". Но хоть для функций всё работало. Если не перегружать. И не шаблонные. И не... а черт с ними, пишем extern C.
И кроме того, Бьярни каждый раз когда ему говорят про именованные аргументы, припоминает что двадцать лет назад он эту булочку уже жевал и она ему не понравилась.
Поэтому ненужные лямбды в стандарте есть, а ненужных именованных аргументов -- нет и не будет.
Re[2]: А почему нет вызова функций с именованными аргументами?
T>Мне кажется, это harmful, хотя бы потому, что заставляет меня иметь имена параметров как часть сигнатуры функции. Отвратительно. В сигнатуру должны входить только типы, имена должны быть up-to-me. Захотел и переименовал, не разрушив существующего кода.
void funct(explicit int int_param, explicit double float_param);
funct(.int_param = 5, .float_param = 0.7); // ok
funct(5, 0.5); // compile error
И пусть будет часть сигнатуры, заодно можно и расширить метаданные по функциям.
Здравствуйте, PM, Вы писали:
PM>Не знаю, чем руководствовались разработчики (может быть это были 2 разных команды), но я не вижу преимуществ в способе задания параметров для CreateWindow перед RegisterClass.
Имхо в случае использования структуры проще добавлять/убирать параметры в будущем.
Re[2]: А почему нет вызова функций с именованными аргументами?
Теоретически, можно было бы паковать аргументы в структуру
foo(FooArgs{ .a = 1, .b = 42 })
А ещё, это напоминает смолток и объектив-си, где фрагменты имени функции чередуются с аргументами
[set_a: 1 b: 42] /* void set_a:b: (int, int) - или что-то типа того */
Интересно, что перегрузка функций с одним именем и разной арностью превращается чисто в лексическую
x and y -- Bool.and(y)
x and: y and: z -- Bool.and:and:(y,z)
x and: y and: z and: t -- Bool.and:and:and:(y,z,t)
x and: y and: z and: t and: u -- Bool.and:and:and:(y,z,t,u)
По правде сказать, C++ная перегрузка по арности почти везде чисто лексическая (компилятор сразу считает арность и дальше смотрит только на подходяще подмножество сигнатур).
Но есть одно место, где она чуть глубже проваливается. Это когда в функцию высшего порядка передаётся имя функции, и к этому имени подбирается сигнатура согласно типу. То есть, нельзя написать foo(and) в расчёте на то, что если foo принимает трёхместную функцию, то and разрешится как and:and:and: — это совсем разные имена.
В остальном же, смолтоковский подход — это именованные аргументы для бедных. Просто в реализации, строго в компиляции, а значит, ошибкоустойчиво.
(За вычетом того, что и смолток, и объектив-си — динамические, и ошибка в имени функции может выплыть иногда только в момент вызова).
Перекуём баги на фичи!
Re[5]: А почему нет вызова функций с именованными аргументами?
Здравствуйте, enji, Вы писали:
E>Здравствуйте, Abyx, Вы писали:
A>>ну возможно я погорячился насчет "обратной совместимости", A>>но тем не менее твоя идея требует чтобы имена параметров были одинаковые в пределах единицы трансляции. A>>а в тоннах легаси кода это не так.
E>Ну прям вот так уж и в тоннах? Разные имена параметров означают, что одна и таже функция определена по разному в двух разных хидерах. Насколько это частое явление?
ситуаций типа
int f(int);
int f(int x) { return x + 1; }
и наоборот
inf f(int x);
int f(int) { return 42; }
— полно, причем иногда в одной единице трансляции будет несколько forward-declaration одной функции
E>Собственно сейчас же как то живут с таким E>
E>/// a.cpp
E>struct T {
E> std::string s;
E>} a;
E>/// b.cpp
E>struct T {
E> int q;
E> std::string s;
E>} b;
E>
это нарушение ODR, с этим долго не живут.
In Zen We Trust
Re[5]: А почему нет вызова функций с именованными аргументами?
Здравствуйте, lgb, Вы писали:
PM>>Не знаю, чем руководствовались разработчики (может быть это были 2 разных команды), но я не вижу преимуществ в способе задания параметров для CreateWindow перед RegisterClass.
lgb>Имхо в случае использования структуры проще добавлять/убирать параметры в будущем.
В общем да, но для RegisterClass нет (см. RegisterClassEx), т.к. в структуре WNDCLASS отсутствует какая-либо информация о версии (поле с именем типа version, cbSize) и для RegisterClassEx пришлось создавать (сюрприз!) WNDCLASSEX
Наверно где-нибудь в "The Old New Thing" Raymond Chen когда-то уже рассказывал историю, почему так исторически сложилось, но на данный момент Win32 API не является образцом отличного дизайна.
Re[6]: А почему нет вызова функций с именованными аргументами?
Здравствуйте, Chorkov, Вы писали:
C>Очень частое: C>
C>// foo.h
C>void foo(int a, int b);
C>//foo.cpp
C>void foo( int/* a */, int/* b */ )
C>{
C> // а и b не используются, поэтому, в определении их закоментировали, чтобы избежать предупреждения компилятора.
C>}
C>
дык клиенту то виден foo.h, а не foo.cpp. А чем закончится попытка вызвать foo(.a=1, .b=2) внутри foo.cpp — вопрос. Может ошибкой компиляции, а может компилятор корректно обработает такую ситуацию — вроде как нет ничего сложного.
void foo(int a, int b);
void foo(int c, int d) {
}
foo(.a=1, .b=2); // вот тут уже однозначно ошибка компиляции
Re[5]: А почему нет вызова функций с именованными аргументами?
U>//a.cpp
U>void f(int, int); // определение где-то в другом месте: в другом файле или либе
U>void g()
U>{
U> f(4, 5);
U>}
U>
ну и какие тут проблемы? Просто нельзя вызвать f с именоваными параметрами. Если у тебя в одной единице f(int a, int b), а в другой — f(int b, int a) — ну попытка вызвать f(.a=1, .b=2) — нарушение ODR. Такое же, как иметь две структуры с одинаковыми именами и разным содержимым.
U>еще если вспомнить про экпортированные функции, то вообще труба, еще и ABI ломать надо
Что не так с экспортированными функциями и зачем ломать abi? Данная штука ведет себя примерно так же, как и параметры по умолчанию — т.е. разворачивается компилятором в обычный вызов функции сразу в месте вызова с той информацией, которая там компилятору доступна.
Re[2]: А почему нет вызова функций с именованными аргументами?
N>Смешались кони, люди. Почему вы спрашиваете про именованные аргументы и в с++ приводите пример функции? N>В си у вас инициализируется структура, а в с++ у вас параметризованная функция.
потому что в с++ есть конструкторы и если разрешить именованные аргументы функций, то чуток дополненный сишный код
struct T {
int a, b;
T(int a, int b) : a(a), b(b) {}
};
T t = {.a = 1, .b=42};
будет компилироваться
Re[2]: А почему нет вызова функций с именованными аргументам
Здравствуйте, B0FEE664, Вы писали:
BFE>Моё мнение такое: экономит надо не время записи, а время чтения. BFE>Запись: E>>f(.a = 1, .b=42); BFE>ничем не лучше, а даже хуже, чем: BFE>
BFE>const int a = 1;
BFE>const int b = 42;
BFE>f(a, b);
это все мило, но кто так пишет? Это просто убивает все однострочники.
Опять же, ты можешь ошибиться и написать f(b, a). А если я напишу f(.b=42, .a=1), то это будет корректно обработано (ну по крайней мере, если применить правила из питона).
Далее, функция может иметь аргументы по умолчанию — void f(a = 1, b = 2, c = 3). И ее можно будет вызывать f(.c=4). Твой вариант с константами тут не поможет...
BFE>Но, что такое a? Что такое b? —
ну вестимо в реальной жизни аргументы не называют a и b ...
BFE>Вызов функции с константами определёнными по месту вызова — это экзотика для хорошего стиля. BFE>Если в программе встречается более чем один вызов функции с одинаковыми не именованными константами, то это уже плохо. Следует либо поименовать константы, либо завернуть вызов функции в другую функцию, например: BFE>
Это к вопросу о нужности лямбд. Зачем нужна лямбда из одной строки, когда можно на 5 строках в другом месте файла изобразить повторно используемый функтор? Вроде как и низачем. Однако ж функторы особо не пишут, и вместо find_if фигачат цикл...
Здравствуйте, Ops, Вы писали:
Ops>А Boost.Parameter вроде ж не только пруф?
про буст я писал в исходном сообщении
BOOST_PARAMETER_NAME(graph) // Note: no semicolon
BOOST_PARAMETER_NAME(visitor)
BOOST_PARAMETER_NAME(root_vertex)
BOOST_PARAMETER_NAME(index_map)
BOOST_PARAMETER_NAME(color_map)
BOOST_PARAMETER_FUNCTION(
(void), // 1. parenthesized return type
depth_first_search, // 2. name of the function template
tag, // 3. namespace of tag types
(required (graph, *) ) // 4. one required parameter, and
(optional // four optional parameters, with defaults
(visitor, *, boost::dfs_visitor<>())
(root_vertex, *, *vertices(graph).first)
(index_map, *, get(boost::vertex_index,graph))
(in_out(color_map), *,
default_color_map(num_vertices(graph), index_map) )
)
)
{
// ... body of function goes here...
// use graph, visitor, index_map, and color_map
}
это ж, имхо, какой-то ужас...
Re[3]: А почему нет вызова функций с именованными аргументам
Здравствуйте, enji, Вы писали:
E>Здравствуйте, B0FEE664, Вы писали:
BFE>>Моё мнение такое: экономит надо не время записи, а время чтения. BFE>>Запись: E>>>f(.a = 1, .b=42); BFE>>ничем не лучше, а даже хуже, чем: BFE>>
BFE>>const int a = 1;
BFE>>const int b = 42;
BFE>>f(a, b);
так как читать такое намного проще читать. Однострочники меня не волнуют.
E>Опять же, ты можешь ошибиться и написать f(b, a). А если я напишу f(.b=42, .a=1), то это будет корректно обработано (ну по крайней мере, если применить правила из питона). E>Далее, функция может иметь аргументы по умолчанию — void f(a = 1, b = 2, c = 3). И ее можно будет вызывать f(.c=4). Твой вариант с константами тут не поможет...
Это хорошие аргументы до тех пор, пока мы не думаем о виртуальных методах.
E>Это к вопросу о нужности лямбд. Зачем нужна лямбда из одной строки, когда можно на 5 строках в другом месте файла изобразить повторно используемый функтор? Вроде как и низачем. Однако ж функторы особо не пишут, и вместо find_if фигачат цикл...
Потому, что для чтения кода важна локальность определения. Редко, когда один и тот же функтор используется более одного раза в программе.
Ну и вообще, предложенный метод не достаточно радикален. Перепутать f(.a=1, .b=42) и f(.a=42, .b=1) тоже довольно просто.
Есть только один по настоящему хардкодный путь: не использовать никаких констант без user-defined суффиксов:
BFE>так как читать такое намного проще читать. Однострочники меня не волнуют.
это нормально. Все равно компактней твоего варианта, плюс не вводит лишних имен. Плюс ошибку в имени определит компилятор
E>>Опять же, ты можешь ошибиться и написать f(b, a). А если я напишу f(.b=42, .a=1), то это будет корректно обработано (ну по крайней мере, если применить правила из питона). E>>Далее, функция может иметь аргументы по умолчанию — void f(a = 1, b = 2, c = 3). И ее можно будет вызывать f(.c=4). Твой вариант с константами тут не поможет... BFE>Это хорошие аргументы до тех пор, пока мы не думаем о виртуальных методах.
а что с ними не так? Такая штука есть например в питоне, в нем все методы виртуальные...
E>>Это к вопросу о нужности лямбд. Зачем нужна лямбда из одной строки, когда можно на 5 строках в другом месте файла изобразить повторно используемый функтор? Вроде как и низачем. Однако ж функторы особо не пишут, и вместо find_if фигачат цикл... BFE>Потому, что для чтения кода важна локальность определения. Редко, когда один и тот же функтор используется более одного раза в программе.
Во во. Та же штука с именованными аргументами...
BFE>Ну и вообще, предложенный метод не достаточно радикален. Перепутать f(.a=1, .b=42) и f(.a=42, .b=1) тоже довольно просто.
Тут по крайней мере четко видно, что есть "а", а что есть "b"
Re[5]: А почему нет вызова функций с именованными аргументам
Проблема с этим способом, как и со всеми похожими способами в С++ та, что имя параметра получается привязанным к типу (как ReplaceOnAdd к bool) и засоряет текущий namespace (нельзя в том же namespace определить новый тип ReplaceOnAdd). На самом деле, с помощью дополнительного класса и макро совсем не трудно сделать и такой синтаксис для именованных параметров:
addElement3(1, ReplaceOnAdd = true);
Но проблемы те же самые, что и у typedef bool ReplaceOnAdd.
Re[7]: А почему нет вызова функций с именованными аргументам
PM>>Кстати, сегодня увидел несколько иной способ использовать булевский параметры без enum:
PM>>[ccode] PM>>typedef bool ReplaceOnAdd;
U>Проблема с этим способом, как и со всеми похожими способами в С++ та, что имя параметра получается привязанным к типу (как ReplaceOnAdd к bool) и засоряет текущий namespace (нельзя в том же namespace определить новый тип ReplaceOnAdd).
Да, пространство имён засоряется, согласен, но не думаю что это сильно критично, ReplaceOnAdd довольно уникальное имя на мой взгляд. А так это достаточно практичный способ для тех, кто не может мириться с bool параметрами. И этот способ работает не только для bool: http://fluxible.blogspot.ru/2014/09/a-trivial-way-to-work-around-boolean.html
Re: А почему нет вызова функций с именованными аргументами?
Да чего уж там функции, на шаблоны тоже неплохо бы продолжить. При куче default параметров сахару не хватает, до Alloc, например, минуя Compare в std::set никак не добраться.
Если извратиться, то тоже обойтись можно, взять те же packed_options в boost::intrusive, но вот как нибудь бы попроще...
C точки зрения реализации проблемы наверное те же, что с аргументами функций, можно же, переобъявляя, их переименовать сто раз.
Тогда что именем считать, first viable или может имя из имплементации? Или любое, но контролировать на совместимость?
void foo(int a, int b);
...
void foo(int b, int a) { // ой, у вас ус отклеился...
}
Re[2]: А почему нет вызова функций с именованными аргументами?
Здравствуйте, sokel, Вы писали:
S>Да чего уж там функции, на шаблоны тоже неплохо бы продолжить. При куче default параметров сахару не хватает, до Alloc, например, минуя Compare в std::set никак не добраться.
+1
S>C точки зрения реализации проблемы наверное те же, что с аргументами функций, можно же, переобъявляя, их переименовать сто раз. S>Тогда что именем считать, first viable или может имя из имплементации? Или любое, но контролировать на совместимость?
Если используется такой вызов, то можно контролировать на "одинаковость" в пределах единицы трансляции
Re[5]: А почему нет вызова функций с именованными аргументам
Здравствуйте, enji, Вы писали:
E>>>Опять же, ты можешь ошибиться и написать f(b, a). А если я напишу f(.b=42, .a=1), то это будет корректно обработано (ну по крайней мере, если применить правила из питона). E>>>Далее, функция может иметь аргументы по умолчанию — void f(a = 1, b = 2, c = 3). И ее можно будет вызывать f(.c=4). Твой вариант с константами тут не поможет... BFE>>Это хорошие аргументы до тех пор, пока мы не думаем о виртуальных методах. E>а что с ними не так? Такая штука есть например в питоне, в нем все методы виртуальные...
Смотрите, сейчас можно написать так:
class A
{
public:
virtual void f(int a) {};
};
class B : public A
{
public:
virtual void f(int b) {};
};
какая функция будет вызвана:
A* p = new B;
p->f(.a = 1);
Или вы хотите поломать совместимость кода?
BFE>>Ну и вообще, предложенный метод не достаточно радикален. Перепутать f(.a=1, .b=42) и f(.a=42, .b=1) тоже довольно просто. E>Тут по крайней мере четко видно, что есть "а", а что есть "b"
С суффиксами это тоже видно. И стандарт менять не надо.
И каждый день — без права на ошибку...
Re[6]: А почему нет вызова функций с именованными аргументами?
Здравствуйте, enji, Вы писали:
E>ну и какие тут проблемы? Просто нельзя вызвать f с именоваными параметрами.
согласен, это согласуется с идеей ниже
E>Если у тебя в одной единице f(int a, int b), а в другой — f(int b, int a) — ну попытка вызвать f(.a=1, .b=2) — нарушение ODR. Такое же, как иметь две структуры с одинаковыми именами и разным содержимым.
это не согласуется с идеей ниже
E>Данная штука ведет себя примерно так же, как и параметры по умолчанию — т.е. разворачивается компилятором в обычный вызов функции сразу в месте вызова с той информацией, которая там компилятору доступна.
этот подход мне кажется вполне работоспособным
с другой стороны, ты выше написал про нарушение ODR, что противоречит этой идее. никакого нарушения не должно быть в примере выше, имена параметров не должны быть частью сигнатуры и проблем с экспортированными функциями опять же не будет
для случаев типа
//a.cppvoid f(int a, int b); // определение где-то в другом месте: в другом файле или либеvoid f(int b, int a);
void g()
{
f(.a = 4, .b = 5); //line (1)
}
надо просто отрубать возможность использования именованных аргументов (не компилировать такой код в строке (1) )
для дефолтных значений параметров ведь в стандарте есть несколько предложений для разруливания конфликтов, когда несколько объявлений идут в одной единице трансляции. можно что-то аналогичное прописать и для имен параметров
Re[6]: А почему нет вызова функций с именованными аргументам
Данная штука ведет себя примерно так же, как и параметры по умолчанию — т.е. разворачивается компилятором в обычный вызов функции сразу в месте вызова с той информацией, которая там компилятору доступна.
, то все очень просто : вызвается метод f из класса A, среди его аргументов ищется a. если он не найден, то компиляция ломается, если найден, то подставляется значение 1. в динамике уже вызовется метод f класса B с аргументом b=1.
Re[7]: А почему нет вызова функций с именованными аргументам
Здравствуйте, uzhas, Вы писали:
BFE>>какая функция будет вызвана: BFE>>
A* p = new B;
p->f(.a = 1);
U>если исходить из U>
U>Данная штука ведет себя примерно так же, как и параметры по умолчанию — т.е. разворачивается компилятором в обычный вызов функции сразу в месте вызова с той информацией, которая там компилятору доступна.
U>, то все очень просто : вызвается метод f из класса A, среди его аргументов ищется a. если он не найден, то компиляция ломается, если найден, то подставляется значение 1. в динамике уже вызовется метод f класса B с аргументом b=1.
Т.е. такой вызов :
B* p = new B;
p->f(.a = 1);
"сломается"?
И каждый день — без права на ошибку...
Re[8]: А почему нет вызова функций с именованными аргументам
Здравствуйте, B0FEE664, Вы писали:
BFE>Или вы хотите поломать совместимость кода?
совместимость кода, имхо, означает, что после некоторого нововведения имеющийся код не сломается. Так как сейчас нет именованных аргументов, то вестимо это условие выполняется. Твой случай ничем не отличается от
void f (int a);
void f (int);
void f(int b) { }
f(.b =1);
и решается точно также — компилятор ругается, если такой код встретился в рамках одной единицы трансляции. Если же разные названия в разных единицах трансляции и функция вызывается с именованными аргументами, то получается что-то вроде нарушения odr. Аналогичные нарушения для классов сейчас не диагностируются.
BFE>>>Ну и вообще, предложенный метод не достаточно радикален. Перепутать f(.a=1, .b=42) и f(.a=42, .b=1) тоже довольно просто. E>>Тут по крайней мере четко видно, что есть "а", а что есть "b"
BFE>С суффиксами это тоже видно. И стандарт менять не надо.
а что за суффиксы?
Re[7]: А почему нет вызова функций с именованными аргументами?
Здравствуйте, uzhas, Вы писали:
U>надо просто отрубать возможность использования именованных аргументов (не компилировать такой код в строке (1) ) U>для дефолтных значений параметров ведь в стандарте есть несколько предложений для разруливания конфликтов, когда несколько объявлений идут в одной единице трансляции. можно что-то аналогичное прописать и для имен параметров
дык и я про тоже — нарушение — не само объявление, а попытка вызова
Re[7]: А почему нет вызова функций с именованными аргументам
вот, к примеру, это интуитивно понятно и красиво для С инициализация структуры. Для плюсов же, в Вашем примере, не совсем понятно что Вы хотите сделать и зачем?