Добрый вечер, возник тут у меня вопрос, а как вы оформляете внутренние(служебные, чистые) функции класса.
Вот некоторые реализации, которые я встречал
1) Просто делаем private: someFunction(); и это соответственно идет в .h, минус никому кроме класса не нужно, будет включаться везде кто использует этот класс
2) Делаем class_inl.h включаем его в cpp, все функции помечаем inline, минус, нет гарантии что они заинлайнятся, появляется новый файл в проекте
3) В cpp делаем
Здравствуйте, Igore, Вы писали:
I>Добрый вечер, возник тут у меня вопрос, а как вы оформляете внутренние(служебные, чистые) функции класса.
Если это просто чистая функция, которой не нужен доступ к членам класса, то прямо в сипипи-шнике, в анонимном пространстве имен. При этом "static" и "inline" являются избыточными.
Здравствуйте, rg45, Вы писали:
R>Здравствуйте, Igore, Вы писали:
I>>Добрый вечер, возник тут у меня вопрос, а как вы оформляете внутренние(служебные, чистые) функции класса.
R>Если это просто чистая функция, которой не нужен доступ к членам класса, то прямо в сипипи-шнике, в анонимном пространстве имен. При этом "static" и "inline" являются избыточными.
Я вот пришёл к выводу, что лучше static, чем анонимное пространство имён.
Тогда в отладчике WinDbg можно легко найти функцию и поставить точку остановки.
С анонимным пространством имён получается имя вроде `anonymous namespace1`::f и отладчик не знает что с этим делать.
Здравствуйте, _NN_, Вы писали:
_NN>Я вот пришёл к выводу, что лучше static, чем анонимное пространство имён.
...
Поддерживаю. Кроме технических ограничений, когда есть более 1 ф-ции/переменной со внутренним связыванием, я предпочитаю видеть эту информацию для каждого объявления/определения, а не для блока. Вот перешёл я через go-to-definition к какой-то ф-ции — и сразу вижу, что она чисто в этом модуле используется, могу без проблем менять интрерфейс, зная, что она снаружи модуля не видна. С unnamed namespace в такой ситуации нужно глядеть выше по контексту.
Здравствуйте, _NN_, Вы писали:
_NN>Я вот пришёл к выводу, что лучше static, чем анонимное пространство имён. _NN>Тогда в отладчике WinDbg можно легко найти функцию и поставить точку остановки. _NN>С анонимным пространством имён получается имя вроде `anonymous namespace1`::f и отладчик не знает что с этим делать. _NN>К тому же есть и проблемы в VS: https://docs.microsoft.com/en-us/visualstudio/debugger/expressions-in-the-debugger?view=vs-2017#anonymous-namespaces _NN>
_NN>Anonymous namespaces are not supported. If you have the following code, you cannot add test to the watch window:
Зато анонимные пространства имен позволяют определять не только функции, но и вообще любые имена с внутренним связываением — классы, перечисления... Тут уже кому что важнее.
Здравствуйте, rg45, Вы писали:
I>>Добрый вечер, возник тут у меня вопрос, а как вы оформляете внутренние(служебные, чистые) функции класса. R>Если это просто чистая функция, которой не нужен доступ к членам класса, то прямо в сипипи-шнике, в анонимном пространстве имен. При этом "static" и "inline" являются избыточными.
Здравствуйте, serg_joker, Вы писали:
_>Поддерживаю. Кроме технических ограничений, когда есть более 1 ф-ции/переменной со внутренним связыванием, я предпочитаю видеть эту информацию для каждого объявления/определения, а не для блока. Вот перешёл я через go-to-definition к какой-то ф-ции — и сразу вижу, что она чисто в этом модуле используется, могу без проблем менять интрерфейс, зная, что она снаружи модуля не видна. С unnamed namespace в такой ситуации нужно глядеть выше по контексту.
Ну анонимные пространства имен ведь не обязательно делать монолитными блоками. Даже наоборот, если определять фунции попближе к месту их использования, как рекомендуют ведущие собаководы, то и код читать легче, и с определением области видимости проблем не возникает, как правило.
Здравствуйте, B0FEE664, Вы писали:
BFE>Почему inline является избыточным?
Ну от ключей компиляции зависит, если быть точным. Типовые настройки таковы, что компилятор и так будет инлайнить функции там, где посчитает это целесообразным ("any suitable" — в msvc). И в этом ему можно доверять, по моему опыту.
Здравствуйте, Igore, Вы писали:
I>Добрый вечер, возник тут у меня вопрос, а как вы оформляете внутренние(служебные, чистые) функции класса.
Если кратко, то 2, 3, 4, в зависимости от ситуации. 1-й случай почти всегда "не вариант", так как "чистые" функции работают с деталями реализации (могут использовать дополнительные зависимости), которые, по возможности, не должны быть видны снаружи и не должны засорять интерфейс класса. Обычно это детали реализации и не нужно их светить лишний раз.
3, 4 — второй по распространенности случай. Если нужно чтобы функция встраивалась, по возможности, то — static inline, иначе — static. Мне static удобен тем, что сначала я набиваю объявления функций в начале файла, потом идет реализация класса использующая функции, а уже потом я реализую сами функции. В случае static — VС, например, "ругается" что отсутствует реализация, что полезно. Так можно быстренько "накидать" реализацию класса, не задумываясь о деталях.
2-ой метод включает 3-й и 4-й. Но я использую его только если реализация "чистых" функций класса уж очень сложная, комплексная, файл начинает разрастаться и затрудняется навигация по коду или несколько родственных классов начинают дублировать функциональность "чистых" функций.
Здравствуйте, _NN_, Вы писали:
_NN>Я вот пришёл к выводу, что лучше static, чем анонимное пространство имён. _NN>Тогда в отладчике WinDbg можно легко найти функцию и поставить точку остановки.
А можно наконец переехать в 21 век и начать писать тесты. Юнит-тесты, функциональные тесты и прочие...
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, _NN_, Вы писали:
_NN>>Я вот пришёл к выводу, что лучше static, чем анонимное пространство имён. _NN>>Тогда в отладчике WinDbg можно легко найти функцию и поставить точку остановки.
L>А можно наконец переехать в 21 век и начать писать тесты. Юнит-тесты, функциональные тесты и прочие...
Хотите сказать, что отладчиком не пользуетесь никогда ?
Никакие тесты не могут покрыть все случаи.
Вот, например, был на компе у клиента вирус , который портил выравнивание стека, а удалять вирус клиент не был готов.
Никакие тесты тут не помогут.
Как поняли, что происходит , добавили обход проблемы и тест для него.
Или ошибки других программ, как например антивирусов. Как это тестировать предлагаете ?
Здравствуйте, _NN_, Вы писали:
_NN>>>Я вот пришёл к выводу, что лучше static, чем анонимное пространство имён. _NN>>>Тогда в отладчике WinDbg можно легко найти функцию и поставить точку остановки.
L>>А можно наконец переехать в 21 век и начать писать тесты. Юнит-тесты, функциональные тесты и прочие...
_NN>Хотите сказать, что отладчиком не пользуетесь никогда ?
При разработке, а вышеотквоченное "помогает" только при "отладке" во время разработки (на самом деле — разработке по-ковбойски) — никогда.
Это если не начинать разговор о том, что static исключает инлайнинг, что может быть важно, когда отлавливаешь микросекунды.
_NN>Никакие тесты не могут покрыть все случаи.
И поэтому их писать вообще не надо, да? Старо как мир.
Как раз правильно написанные тесты покрывают абсолютно все возможные случаи для тестируемого юнита. Чего отладчиком не проверить никогда. При этом они прогоняются при каждой сборке и являются первой стадией верификации ака регрессивного тстирования, что вручную отладчиком... ну даже несерьезно обсуждать.
И даже когда изначально поленился покрыть все сценарии в тестах, наличие уже покрытых тестами сценариев позволяет методом исключения найти проблему намного быстрее.
_NN>Вот, например, был на компе у клиента вирус , который портил выравнивание стека, а удалять вирус клиент не был готов. _NN>Никакие тесты тут не помогут. _NN>Как поняли, что происходит , добавили обход проблемы и тест для него.
А если у него в серверной пожар, который он тушить не готов, то вы тоже напишете обход?
_NN>Или ошибки других программ, как например антивирусов. Как это тестировать предлагаете ?
Не поверишь, но во многих случаях это тоже можно выявлять и доказывать тестами.
Здравствуйте, Igore, Вы писали:
I>Добрый вечер, возник тут у меня вопрос, а как вы оформляете внутренние(служебные, чистые) функции класса.
I>... I>Вроде как все отлично, все должно встроится, хотя она и помечена как static. I>Плюсы, h чистый, все должно остаться в cpp
I>Хочется совета, кто что использует или что было бы хорошо использовать.
У анонимных пространств имён, впрочем, как и у статических функций, есть недостаток. На некоторых проектах для ускорения сборки используется так называемая техника unity builds, когда билд система создаёт один (или несколько, в зависимости от количества ядер) .cpp файл, в который уже включаются все остальные .cpp файлы из проекта. Так вот, при использовании такой техники возможнны конфликты имён. Мы с таким сталкивались, когда начали использовать cotire.
Здравствуйте, SaZ, Вы писали:
SaZ>У анонимных пространств имён, впрочем, как и у статических функций, есть недостаток. На некоторых проектах для ускорения сборки используется так называемая техника unity builds, когда билд система создаёт один (или несколько, в зависимости от количества ядер) .cpp файл, в который уже включаются все остальные .cpp файлы из проекта. Так вот, при использовании такой техники возможнны конфликты имён. Мы с таким сталкивались, когда начали использовать cotire.
А как в таком случае спасают static функции, ведь они тоже не обязаны быть уникальными для разных .cpp ?
Здравствуйте, Videoman, Вы писали:
V>А как в таком случае спасают static функции, ведь они тоже не обязаны быть уникальными для разных .cpp ?
Так я же и написал, что не спасают. В нашем случае поступали очень просто, в большинстве случаев делали static private функции внутри класса. Да, интерфейс загаживался, но это было не критично.
Здравствуйте, SaZ, Вы писали:
SaZ>У анонимных пространств имён, впрочем, как и у статических функций, есть недостаток. На некоторых проектах для ускорения сборки используется так называемая техника unity builds, когда билд система создаёт один (или несколько, в зависимости от количества ядер) .cpp файл, в который уже включаются все остальные .cpp файлы из проекта. Так вот, при использовании такой техники возможнны конфликты имён. Мы с таким сталкивались, когда начали использовать cotire.
V>Если кратко, то 2, 3, 4, в зависимости от ситуации. 1-й случай почти всегда "не вариант", так как "чистые" функции работают с деталями реализации (могут использовать дополнительные зависимости), которые, по возможности, не должны быть видны снаружи и не должны засорять интерфейс класса. Обычно это детали реализации и не нужно их светить лишний раз.
А почему не вариант? Может просто объявить private функцию и не порождать монстров? Стоит ли игра свеч?
Здравствуйте, rg45, Вы писали:
R>Как по мне, то нафиг-нафиг такие ускорения.
Ну мы всякое пробовали. Изначально была ситуация, когда билды игры под андройд могли занимать до 9 часов. Решали всевозможными путями. Прикручивали PCH, поняли что фигня. Делали самописные кэши для текстур, что очень помогало. Увеличивали зоопарк билд серверов. Пробовали Incredibuild, ccache (который пропатчили для нормальной работы под винду). В конечном счёте все махинации, включая юнити билды сделал сборку за приемлемое время: от 4 минут в лучшем случае до 20 минут с конвертацией всех текстур.
Здравствуйте, SaZ, Вы писали:
SaZ>Ну мы всякое пробовали. Изначально была ситуация, когда билды игры под андройд могли занимать до 9 часов. Решали всевозможными путями. Прикручивали PCH, поняли что фигня. Делали самописные кэши для текстур, что очень помогало. Увеличивали зоопарк билд серверов. Пробовали Incredibuild, ccache (который пропатчили для нормальной работы под винду). В конечном счёте все махинации, включая юнити билды сделал сборку за приемлемое время: от 4 минут в лучшем случае до 20 минут с конвертацией всех текстур.
А каков вклад юнити билдов в общее ускорение, можно как-то оценить? Вот если убрать только их, какое время сборки получится?
Здравствуйте, rg45, Вы писали:
R>А каков вклад юнити билдов в общее ускорение, можно как-то оценить? Вот если убрать только их, какое время сборки получится?
С ходу не вспомню, это года 3 назад было. Я спрошу у бывших коллег, потом отпишусь. Сборка основного движка вместе с thirdpary примерно в 10 раз, сборка Qt редактора примерно в 2-3 раза.
Надо понимать, что это в первую очередь актуально для сборки с нуля на билд серверах. Мы отказались от PCH, потому что с ним не дружил IncrediBuild.
Основной прирост достигался, насколько я помню, не для скорости компиляции а для скорости линковки.
Здравствуйте, PavelCH, Вы писали:
PCH>А почему не вариант? Может просто объявить private функцию и не порождать монстров? Стоит ли игра свеч?
А зачем мне объявлять функцию в классе, если она полностью не зависит от класса, а нужно, только, выполнить полезное действие в реализации?
Какие преимущества:
— Не засоряется пространств имен класса. Private хоть и защищает от вызова снаружи, но участвует в перегрузке. Можно использовать короткие названия, понятные из контекста, во всех наследниках и не париться.
— Вызывая такую функцию, я полностью уверен что она не меняет инвариант класса. Т.е. на лицо меньшая связность, да еще и компилятор это проверит.
— Реализация функции может требовать дополнительный инклюды, которые не нужны в публичном интерфейсе класса, что будет засорять пространство имен и, возможно, приводить к перекомпиляции.
PCH>Стоит ли игра свеч?
О каких свечах идет речь? Если что, писанины меньше, перекомпиляций тоже.
V>Какие преимущества: V>- Не засоряется пространств имен класса. Private хоть и защищает от вызова снаружи, но участвует в перегрузке. Можно использовать короткие названия, понятные из контекста, во всех наследниках и не париться.
Не совсем Вас понял. Можете привести пример? Насколько я помню там работает так:
struct A {
int get() { return 1; }
};
struct B : A {
int get(int n) { return n; }
};
int main() {
B b;
return b.get(); // Тут ошибка компиляции
}
V>- Вызывая такую функцию, я полностью уверен что она не меняет инвариант класса. Т.е. на лицо меньшая связность, да еще и компилятор это проверит.
Ну она же не доступна наружу. Возможно это не надо? V>- Реализация функции может требовать дополнительный инклюды, которые не нужны в публичном интерфейсе класса, что будет засорять пространство имен и, возможно, приводить к перекомпиляции.
Те функции, которые требуют дополнительные инклюды, я выделяю в отдельные cpp файлы. В итоге это снижает время компиляции, если я ничего не меняю эта часть функционала не перекомпилируется. PCH>>Стоит ли игра свеч? V>О каких свечах идет речь? Если что, писанины меньше, перекомпиляций тоже.
Не уверен что метод 3 занимает меньше писанины. Насчет перекомпиляция тоже вопрос. Вообще я стараюсь делать служебные функции static и невидимые в h — но они конечно не имеют доступа к private членам класса. Если он нужен и только в этом случае применяю private функции класса.
Здравствуйте, PavelCH, Вы писали:
PCH>Не совсем Вас понял. Можете привести пример? Насколько я помню там работает так:
... ох, там тонкие моменты были когда наталкивался, сейчас не могу сразу воссоздать. Но это и не важно. Ясно что пространство имен в .cpp потенциально меньше пространства имен всего класса.
PCH>Ну она же не доступна наружу. Возможно это не надо?
Важно, не важно — общий принцип разработки гибкого и поддерживаемого кода, это маленькая связность, чем меньше тем лучше. Меньше связность — меньше контекста держать в голове и меньше вероятность нечаянно сломать.
PCH>Те функции, которые требуют дополнительные инклюды, я выделяю в отдельные cpp файлы. В итоге это снижает время компиляции, если я ничего не меняю эта часть функционала не перекомпилируется.
Т.е. если вдруг вам понадобилась одна функция, то вы создаёте для нее отдельный файл .cpp, а если, в процессе рефакторинга, она перестала быть нужна, вы всё обратно объединяете? Вы думаете это проще?
PCH>Не уверен что метод 3 занимает меньше писанины. Насчет перекомпиляция тоже вопрос. Вообще я стараюсь делать служебные функции static и невидимые в h — но они конечно не имеют доступа к private членам класса. Если он нужен и только в этом случае применяю private функции класса.
Слушайте, но бывают конечно классы, легкие снаружи, но сложные внутри, которые в реализации используют кучу функций и даже других классов. И вот в этом случае разделение на дополнительные файлы .h и.cpp оправдано, но применять такую стратегию постоянно — слишком, на мой взгляд.
Здравствуйте, PavelCH, Вы писали:
PCH>Не совсем Вас понял. Можете привести пример? Насколько я помню там работает так: PCH>Ну она же не доступна наружу. Возможно это не надо? PCH>Те функции, которые требуют дополнительные инклюды, я выделяю в отдельные cpp файлы. В итоге это снижает время компиляции, если я ничего не меняю эта часть функционала не перекомпилируется. PCH>>>Стоит ли игра свеч? PCH>Не уверен что метод 3 занимает меньше писанины. Насчет перекомпиляция тоже вопрос. Вообще я стараюсь делать служебные функции static и невидимые в h — но они конечно не имеют доступа к
Вот в этой книжке (см. рекомендацию №44) сформулирован несложный критерий, когда следует делать функцию членом класса. Звучит этот критерий примерно так: "делайте функию членом класса в том случае, когда у вас нет другого выхода". А во всех остальных случаях, соответственно, не делайте. И можно вести бесконечно долгие дискуссии на эту тему, приводя бесчисленные доводы "за" и "против", но убедиться в истинности этого правила можно только на личном опыте.
Здравствуйте, Igore, Вы писали:
I>Добрый вечер, возник тут у меня вопрос, а как вы оформляете внутренние(служебные, чистые) функции класса.
I>1) Просто делаем private: I>2) Делаем class_inl.h I>3) В cpp делаем namespace { I>4) Увидел сейчас static inline inner()
Здравствуйте, B0FEE664, Вы писали:
I>>Добрый вечер, возник тут у меня вопрос, а как вы оформляете внутренние(служебные, чистые) функции класса.
I>>1) Просто делаем private: I>>2) Делаем class_inl.h I>>3) В cpp делаем namespace { I>>4) Увидел сейчас static inline inner()
BFE>5) Лямбда.
Даже не знаю, уместно ли вспоминать о лямбдах в данном контесте. Все-таки, лямбда — это элемент парадигмы, позволяющей оперировать функциями как данными, но никак не средство оформления. И по отношению к лямбдам возникают почти все те же вопросы, что и по отношению к функциям: какая область видимости, какое связывание, член или не член...
Здравствуйте, rg45, Вы писали:
BFE>>5) Лямбда.
R>Даже не знаю, уместно ли вспоминать о лябмдах в данном контесте. Все-таки, лябмда — это элемент парадигмы, позволяющей оперирровать функциями как данными. Но никак не средство оформления. И по отношению к лямбдам возникают почти все те же вопросы, что и по отношению к функциям: какая область видимости, какое связывание, член или не член...
Все приведённые примеры темы имеют вызов из одного метода. В этом случае функцию можно оформить прямо внутри метода в виде лямбды (не захватывая никаких переменных): никаких проблем с видимостью, связыванием и членством.
Здравствуйте, B0FEE664, Вы писали:
BFE>Все приведённые примеры темы имеют вызов из одного метода. В этом случае функцию можно оформить прямо внутри метода в виде лямбды (не захватывая никаких переменных): никаких проблем с видимостью, связыванием и членством.
Можно-то можно, вот только нужно ли. Я понимаю, если лямбда передается параметром в какую-то другую функцию, тогда, конечно, ее использование обправдано, ибо ради этого лямбды и придуманы, собственно. А опредлить лямбду только для того, чтобы тут же ее и вызвать — польза от такого использования лично для меня сомнительна. Обычная свободная функция в анонимном пространстве имен — вот что самое оно для таких случаев — код получается и проще, и компактнее, и читабельнее. Хотя, все субъективно, конечно.
Здравствуйте, rg45, Вы писали:
R>Можно-то можно, вот только нужно ли. Я понимаю, если лямбда передается параметром в какую-то другую функцию, тогда, конечно, ее использование обправдано, ибо ради этого лямбды и придуманы, собственно. А опредлить лямбду только для того, чтобы тут же ее и вызвать — польза от такого использования лично для меня сомнительна. Обычная свободная функция в анонимном пространстве имен — вот что самое оно для таких случаев — код получается и проще, и компактнее, и читабельнее. Хотя, все субъективно, конечно.
Ну вот не нравится, и все тут. Не для того аккумулятор покупали, чтоб капусту солить А потом приходится выслушивать, мол "переусложнизмом" С++ страдает. Так понятно, если применять возможности языка не по назначению, то так оно и будет восприниматься.
Ну, хорошо, согласен, полльза от такого применения лямбд есть: это позволяет давать функциям (лямбдам) максимально простые имена, не засоряя пространство имен, пусть даже анонимное. Но, что мне все же не нравится, это то, что мы исплоьзуем лямду не потому, что нам нужна лябмда, как таковая, а просто потому, что правила языка не позволяют нам определять функции внутри других функций. Нам же никогда не прийдет в голову написать лямбду в пространстве имен там, где достаточно обычной функции. Вот поэтому такое использование лямбд кажется мне нецелевым. Хотя и оправданным в некоторых случаях, таких как этот.
Здравствуйте, B0FEE664, Вы писали:
R>>Если это просто чистая функция, которой не нужен доступ к членам класса, то прямо в сипипи-шнике, в анонимном пространстве имен. При этом "static" и "inline" являются избыточными.
BFE>Почему inline является избыточным?
Потому, что при типичных настройках оптимизации компилятор с линкером сами решают что подставлять, а что нет, главное что бы определение подставляемого (или иначе используемого, кстати) было в точке вызова доступно.
А слова вроде static и inline влияют на связывание, видимость, ODR и тому подобные вещи, а не на то, будет подставляться то, что видно в точке вызова или нет...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, SaZ, Вы писали:
SaZ>Так я же и написал, что не спасают. В нашем случае поступали очень просто, в большинстве случаев делали static private функции внутри класса. Да, интерфейс загаживался, но это было не критично.
можно было просто для класса MyClass такие функции называть MyClass_f или положить их в namespace MyClass_private и не загаживать интерфейс.
Да, сделать это можно полуавтоматически, например скриптом.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Потому, что при типичных настройках оптимизации компилятор с линкером сами решают что подставлять, а что нет, главное что бы определение подставляемого (или иначе используемого, кстати) было в точке вызова доступно.
А последние несколько лет компиляторы умеют даже инлайнить функции, определение которых располагается после точки использования, в той же единице трансляции. Наиболее распространенный сценарий — это обращение к приватным функциям-членам изнутри класса — инлайнинг пройдет *как надо*, независимо от последовательности определений всех функций членов в рамках единицы трансляции. Блягодаря этому, можно не заморачиваться и выбирать последовательность определений, исходя из соображений лучшего восприятия кода.
Здравствуйте, rg45, Вы писали:
R>Ну вот не нравится, и все тут. Не для того аккумулятор покупали, чтоб капусту солить
Да вроде нормальное решение — обычная вложенная функция. Они бывают очень кстати как раз для уменьшения ненужной сложности: не засоряется scope файла. До лямбд было совсем не то: или изгаляться с макросами, или с локальными классами-функторами, которые громоздки и не имеют автоматического доступа к локальным переменным объемлющей функции; поэтому обычно и не заморачивались.
В Go, конечно, это делается элегантнее:
func something() {
inc := func(x int) int { return x + 1 }
i := 1
fmt.Println(inc(i)) // prints 2
}
Здравствуйте, Igore, Вы писали:
I>Добрый вечер, возник тут у меня вопрос, а как вы оформляете внутренние(служебные, чистые) функции класса.
... I>Хочется совета, кто что использует или что было бы хорошо использовать.
Здравствуйте, rg45, Вы писали:
R>Ну, хорошо, согласен, полльза от такого применения лямбд есть: это позволяет давать функциям (лямбдам) максимально простые имена, не засоряя пространство имен, пусть даже анонимное. Но, что мне все же не нравится, это то, что мы исплоьзуем лямду не потому, что нам нужна лябмда, как таковая, а просто потому, что правила языка не позволяют нам определять функции внутри других функций. Нам же никогда не прийдет в голову написать лямбду в пространстве имен там, где достаточно обычной функции. Вот поэтому такое использование лямбд кажется мне нецелевым. Хотя и оправданным в некоторых случаях, таких как этот.
Здравствуйте, B0FEE664, Вы писали:
BFE>>>5) Лямбда.
R>>Даже не знаю, уместно ли вспоминать о лябмдах в данном контесте. Все-таки, лябмда — это элемент парадигмы, позволяющей оперирровать функциями как данными. Но никак не средство оформления. И по отношению к лямбдам возникают почти все те же вопросы, что и по отношению к функциям: какая область видимости, какое связывание, член или не член...
BFE>Все приведённые примеры темы имеют вызов из одного метода. В этом случае функцию можно оформить прямо внутри метода в виде лямбды (не захватывая никаких переменных): никаких проблем с видимостью, связыванием и членством.
Это всего лишь примеры, подразумевается многократное использование внутри cpp файла, и лямбда тут може быть только если функция маленькая и сама лямбда маленькая.
Здравствуйте, Igore, Вы писали:
I>Это всего лишь примеры, подразумевается многократное использование внутри cpp файла, и лямбда тут може быть только если функция маленькая и сама лямбда маленькая.
Вчера перед сном листал стандарт, увидел пример:
auto vglambda = [](auto printer)
{
return [=](auto&& ... ts)
{
printer(std::forward<decltype(ts)>(ts)...); // OK: ts is a function parameter packreturn [=]()
{
printer(ts ...);
};
};
};
auto p = vglambda( [](auto v1, auto v2, auto v3) { std::cout << v1 << v2 << v3; } );
auto q = p(1, ’a’, 3.14); // OK: outputs 1a3.14
q(); // OK: outputs 1a3.14
Смотря на такое мне совсем не кажется, что лямбда должна быть маленькой.
BFE>Вчера перед сном листал стандарт, увидел пример: BFE>Смотря на такое мне совсем не кажется, что лямбда должна быть маленькой.
Стандарт описывает требования к языку и поведеннию программ, но никак не к стилю кодирования. Делать выводы о хорошем стиле использования лямбд по этим примерам, это примерно то же самое, что пытаться понять, как правильно пользоваться оператором goto, по примерам из стандарта.
Здравствуйте, rg45, Вы писали:
R>Стандарт описывает требования к языку и поведеннию программ, но никак не к стилю кодирования. Делать выводы о хорошем стиле использования лямбд по этим примерам, это примерно то же самое, что пытаться понять, как правильно пользоваться оператором goto, по примерам из стандарта.
Кстати, про goto. Лямбду можно использовать для замены goto.
Что же касается стиля и использование не по назначению — посмотрите на SFINAE.
Здравствуйте, B0FEE664, Вы писали:
BFE>Что же касается стиля и использование не по назначению — посмотрите на SFINAE.
SFINAE, как и лямбды, тоже можно использовать по-разному. Одно дело, когда SFINAE используется там, где достаточно простой специализации/перегрузки, и совсем другое, когда альтернативу трудно подобрать без значительных переделок и редизайна.
Кстати, лямбды нельзя использовать в списках инициализации, а частенько бывает нужно вызвать "внутреннюю" функцию. Так что они не годятся как универсальный подход. Получается надежней [inline] static функций ничего нет .