Когда локальная лямбда захватывается другой лямбдой, должна ли она быть по значению или по ссылке?

#c #lambda

Вопрос:

У меня есть функция, которая объявляет некоторые локальные лямбда-переменные, и я хочу составить их в другой лямбде. Простой пример:

 auto aggressiveModel = [this](const Paramsamp; params) -gt; double { ... }; auto lazyModel = [this](const Paramsamp; params) -gt; double { ... }; auto model = [ ((???))aggressiveModel, ((???))lazyModel](const Paramsamp; params) { return std::min(aggressiveModel(params), lazyModel(params)); };  

В model(...) лямбде следует ли захватывать другие лямбды по значению, ссылке или по умолчанию? Что означают спецификаторы в контексте переменных lamba?

Комментарии:

1. Собираетесь ли вы возвращаться model за пределы области, в которой он объявлен?

2. @NathanOliver В данном случае нет, но я ищу более общие рекомендации, чтобы понять, что означает захват в контексте ламбас.

3. Тогда в этом случае я бы предложил захватить по ссылке. В целом, однако, если лямбда может пережить то, что вы фиксируете по ссылке, то вы должны фиксировать по значению, иначе у вас может быть висячая ссылка.

4. Они означают то же самое, что и в контексте не-лямбд. Лямбды не являются чем-то особенным.

5. Захват лямбды на самом деле является объектом, являющимся сценами, подумайте об этом таким образом. Применяются те же правила определения области действия и срока службы.

Ответ №1:

Лямбды-это просто более простые способы написания функторов объектов в старом стиле. aggressiveModel эквивалентно:

 struct AggressiveModel {  AggressiveModel(Object* _this)  : _this(_this)  {  }   Object* _this;   double operator()(const Paramsamp; params)  {  ...  } };  AggressiveModel aggressiveModel(this);  

aggressiveModel поэтому копирование-это просто вопрос копирования захваченной this переменной, а не то, о чем вам следует беспокоиться. Очевидно, что лямбда с более длинным списком захвата или с более дорогими для копирования объектами будет отличаться. Хотя даже в этом случае компилятор может оптимизировать копии, особенно если mutable это не так, и компилятор, следовательно, знает, что ни одно из значений не изменится, и это может доказать, что исходная лямбда не выходит за рамки.

Как и в случае с любым другим объектом, использование ссылки на лямбду позволит избежать копирования, но вы должны убедиться, что объект остается в области действия в течение всего срока действия ссылки.