На локальную переменную со вложенной функцией нельзя ссылаться внутри тела лямбды
У вас на каждый вызов qwer вызывается конструктор чтобы переобразовать лямбду в std::function . Лямбда при этом копируется. Вот вы и имеете три копии лямбды и у каждой своя копия x .
Разные типы, поэтому всегда будет конструировать std::function . Передавай через perfect forwarding, проверяй тип через концепт или метафункцию enable_if (для C++17 и ниже).
2 ответа 2
Class template std::function is a general-purpose polymorphic function wrapper. Instances of std::function can store, copy, and invoke any CopyConstructible Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.
Если я правильно понимаю, там создается копия, потому что тип у f другой. Но достаточно сделать явный тип
и все работает как нужно.
Получается если я определил лямбду через auto , то нет никакой разницы между void qwer(std::function a) и void qwer(const std::function &a) ? Ведь и так и так будут созданы копии и вывод на экран будет 1 1 1 .
если я правильно понимаю, что происходит, то тип лямбды и std::function не совпадают, но есть преобразование, которое может сделать из первого второе. И это преобразование - копирование.
Объясню немного 2 вопрос.
Когда вы передаёте в функцию qwer лямбду, то т.к. она принимает аргумент типа function , то создается временный объект на который и ведет ссылка.
Вы можете удостоверится в этом добавив такую строчку в функцию qwer :
Сама лямбда у вас захватывает x по значению, по этому в каждом временном объекте своя копия x , нужно чтобы лямбда захватывала его по ссылке &x .
Поподробней и более умным языком написано тут.
То есть в вашем случае ссылка function& ведет на временный объект из-за различий в типах. А сама лямбда захватывает x по значению, а не по ссылке, по этому каждый временный объект работает с копией x .
Что такое лямбда-выражение в C ++ 11? Когда я буду использовать один? Какой класс проблем они решают, что было невозможно до их введения?
Несколько примеров и вариантов использования будут полезны.
Решение
C ++ включает в себя полезные общие функции, такие как std::for_each а также std::transform , что может быть очень удобно. К сожалению, они также могут быть довольно громоздкими в использовании, особенно если функтор Вы хотели бы применить уникальные для конкретной функции.
Если вы используете только f однажды и в этом конкретном месте кажется излишним писать целый класс, просто чтобы сделать что-то тривиальное и одноразовое.
В C ++ 03 вы можете написать что-то вроде следующего, чтобы сохранить функтор локальным:
однако это не разрешено, f не может быть передано шаблон функция в C ++ 03.
В C ++ 11 введены лямбда-выражения, позволяющие написать встроенный анонимный функтор для замены struct f , Для небольших простых примеров это может быть чище для чтения (оно хранит все в одном месте) и потенциально проще для обслуживания, например в простейшей форме:
Лямбда-функции являются просто синтаксическим сахаром для анонимных функторов.
Типы возврата
В простых случаях для вас выводится тип возврата лямбды, например:
однако, когда вы начнете писать более сложные лямбды, вы быстро столкнетесь со случаями, когда компилятор не может определить тип возвращаемого значения, например:
Чтобы решить эту проблему, вы можете явно указать тип возвращаемого значения для лямбда-функции, используя -> T :
До сих пор мы не использовали ничего, кроме того, что было передано лямбде в нем, но мы также можем использовать другие переменные в лямбде. Если вы хотите получить доступ к другим переменным, вы можете использовать предложение захвата ( [] выражения), который до сих пор не использовался в этих примерах, например:
Вы можете захватить как по ссылке, так и по значению, которое вы можете указать, используя & а также = соответственно:
- [&epsilon] захватить по ссылке
- [&] захватывает все переменные, используемые в лямбда-выражениях по ссылке
- [=] захватывает все переменные, используемые в лямбда-выражениях, по значению
- [&, epsilon] захватывает переменные, как с помощью [&], но эпсилон по значению
- [=, &epsilon] захватывает переменные как с [=], но эпсилон по ссылке
Сгенерированный operator() является const по умолчанию подразумевается, что захват будет const когда вы получаете к ним доступ по умолчанию. Это приводит к тому, что каждый вызов с одним и тем же вводом будет давать один и тот же результат, однако вы можете пометить лямбду как mutable просить, чтобы operator() что производится не const ,
Другие решения
Концепция лямбда-функции в C ++ берет свое начало в лямбда-исчислении и функциональном программировании. Лямбда — это безымянная функция, которая полезна (в реальном программировании, а не в теории) для коротких фрагментов кода, которые невозможно повторно использовать и которые не стоит называть.
В C ++ лямбда-функция определяется следующим образом
или во всей красе
[] это список захвата, () список аргументов и <> тело функции.
Список захвата
Список захвата определяет, что снаружи лямбды должно быть доступно внутри тела функции и как.
Это может быть либо:
- значение: [x]
- ссылка [&Икс]
- любая переменная в настоящее время в области видимости по ссылке [&]
- такой же, как 3, но по значению [=]
Вы можете смешать любое из вышеперечисленного в списке через запятую [x, &y] ,
Список аргументов
Список аргументов такой же, как и в любой другой функции C ++.
Тело функции
Код, который будет выполнен, когда лямбда будет вызвана.
Возвращаемый тип удержания
Если лямбда имеет только один оператор возврата, тип возврата может быть опущен и имеет неявный тип decltype(return_statement) ,
изменчивый
Если лямбда помечена как изменяемая (например, []() mutable < >) разрешено изменять значения, захваченные по значению.
Библиотека, определяемая стандартом ISO, в значительной степени выигрывает от лямбд и повышает удобство использования на несколько тактов, поскольку теперь пользователям не нужно загромождать свой код маленькими функторами в некоторой доступной области видимости.
В C ++ 14 лямбд были расширены различными предложениями.
Инициализированные лямбда-захваты
Элемент списка захвата теперь можно инициализировать с помощью = , Это позволяет переименовывать переменные и захватывать при перемещении. Пример взят из стандарта:
и один взят из Википедии, показывающий, как захватить с std::move :
Универсальные лямбды
Лямбды теперь могут быть родовыми ( auto будет эквивалентно T здесь, если
T были аргументы шаблона типа где-то в окружающей области видимости):
Улучшено вычитание типа возврата
C ++ 14 позволяет выводить типы возврата для каждой функции и не ограничивает ее функциями вида return expression; , Это также распространяется на лямбды.
Лямбда-выражения обычно используются для инкапсуляции алгоритмов, чтобы их можно было передать другой функции. Тем не мение, можно выполнить лямбду сразу после определения:
Это делает лямбда-выражения мощный инструмент для рефакторинга сложных функций. Вы начинаете с обертывания секции кода в лямбда-функции, как показано выше. Процесс явной параметризации может затем выполняться постепенно с промежуточным тестированием после каждого шага. Как только у вас будет полностью параметризованный кодовый блок (что продемонстрировано удалением & ), вы можете переместить код во внешнее местоположение и сделать его нормальной функцией.
Точно так же вы можете использовать лямбда-выражения для инициализировать переменные на основе результата алгоритма…
Как способ разделения логики вашей программы, Вы можете даже найти полезным передать лямбда-выражение в качестве аргумента другому лямбда-выражению …
Лямбда-выражения также позволяют создавать именованные вложенные функции , что может быть удобным способом избежать дублирования логики. Использование именованных лямбд также, как правило, немного проще для глаз (по сравнению с анонимными встроенными лямбдами) при передаче нетривиальной функции в качестве параметра другой функции. Примечание: не забывайте точку с запятой после закрывающей фигурной скобки.
Если последующее профилирование обнаруживает значительные издержки инициализации для объекта функции, вы можете переписать это как обычную функцию.
ответы
Q: Что такое лямбда-выражение в C ++ 11?
Q: Когда я буду использовать один?
В: Какой класс проблем они решают, что было невозможно до их появления?
A: Это какой-то синтаксический сахар, как перегрузка операторов вместо функций для пользовательских добавить, subrtact операции … Но это экономит больше строк ненужного кода для переноса 1-3 строк реальной логики в некоторые классы и т. д.! Некоторые инженеры считают, что если число строк меньше, то вероятность ошибиться в нем меньше (я тоже так думаю)
Пример использования
Дополнения о лямбдах, не подпадающие под вопрос. Игнорируйте этот раздел, если вы не заинтересованы
1. Захваченные значения. Что вы можете поймать
1.1. Вы можете ссылаться на переменную со статической продолжительностью хранения в лямбдах. Все они захвачены в плен.
1.3. Вы можете захватить ссылки. & — в этом контексте означают ссылку, а не указатели.
1.4. Существует нотация для захвата всех нестатических переменных по значению или по ссылке
1,5. Существует нотация для захвата всех нестатических переменных по значению или по ссылке и указания чего-либо. Больше.
Примеры:
Захватить все нестатические переменные по значению, но по ссылке захватить Param2
Захватить все нестатические переменные по ссылке, но по значению Param2
2. Возвращаемый тип удержания
2.1. Лямбда-тип возврата может быть выведен, если лямбда-выражение является одним выражением. Или вы можете явно указать это.
Если лямбда имеет более одного выражения, тип возврата должен быть указан через конечный тип возврата.
Кроме того, подобный синтаксис может быть применен к автоматическим функциям и функциям-членам.
3. Захваченные значения. Что вы не можете захватить
3.1. Вы можете захватывать только локальные переменные, а не переменную-член объекта.
4.1 !! Лямбда не указатель на функцию и не анонимная функция, но захват менее Лямбды могут быть неявно преобразованы в указатель на функцию.
постскриптум
Вы можете написать функцию на месте, чтобы использовать ее так же, как переданную ниже для применения:
Но вы не можете сделать это:
из-за ограничений в стандарте C ++ 11. Если вы хотите использовать снимки, вы должны полагаться на библиотеку и
(или какой-нибудь другой библиотеке STL, такой как алгоритм, чтобы получить ее косвенно), а затем работать с std :: function вместо передачи нормальных функций в качестве параметров, подобных этому:
What is a lambda expression?
лямбда-выражение, иногда также упоминается как лямбда
функционировать или (строго говоря неправильно, но в разговорной речи) как
лямбда, это упрощенное обозначение для определения и использования объект анонимной функции. Вместо определения именованного класса с помощью оператора (), создания объекта этого класса и, наконец,
вызывая его, мы можем использовать сокращение.
When would I use one?
Это особенно полезно, когда мы хотим передать операцию как
аргумент алгоритма. В контексте графических пользовательских интерфейсов
(и в других местах) такие операции часто называют обратные вызовы.
What class of problem do they solve that wasn't possible prior to their introduction?
Здесь я думаю, что каждое действие, выполненное с помощью лямбда-выражения, может быть решено без них, но с гораздо большим количеством кода и гораздо большей сложностью. Лямбда-выражение — это способ оптимизации вашего кода и способ сделать его более привлекательным. Как грустно от Страуступа:
эффективные способы оптимизации
Some examples
или через функцию
если вам нужно, вы можете назвать lambda expression как ниже:
Или предположим другой простой пример
будет генерировать следующий
[] — это список захвата или lambda introducer : если lambdas не требуют доступа к их местной среде, мы можем использовать его.
Цитата из книги:
Первый символ лямбда-выражения всегда [. Лямбда
Интродуктор может принимать различные формы:• []: пустой список захвата. это
подразумевает, что никакие локальные имена из окружающего контекста не могут быть использованы
в лямбда-теле. Для таких лямбда-выражений данные получаются из
аргументы или из нелокальных переменных.• [&]: неявно захватить
ссылка. Все местные имена могут быть использованы. Все локальные переменные
доступ по ссылке.• знак равно: неявный захват по значению. Все местные
имена могут быть использованы. Все имена относятся к копиям локальных переменных
берется в точке вызова лямбда-выражения.• [Снимаемого список]: явный захват; список захвата — это список имен локальных переменных, которые должны быть захвачены (то есть, сохранены в объекте) по ссылке или по значению. Переменные с именами, которым предшествует & захвачены
ссылка. Другие переменные фиксируются по значению. Список захвата может
также содержат это и имена, сопровождаемые … как элементы.• [&, захват-список]: неявно захватывает по ссылке все локальные переменные с именами, не упомянутыми в списке. Список захвата может содержать это. Перечисленным именам не может предшествовать &, Переменные, названные в
список захвата захвачен по значению.• [=, список захвата]: неявно захватывает по значению все локальные переменные с именами, не упомянутыми в списке. Список захвата не может содержать это. Перечисленным названиям должен предшествовать &, Переменные, названные в списке захвата, захватываются по ссылке.
Обратите внимание, что локальному имени предшествует & всегда захвачен
ссылка и местное название, которому не предшествует & всегда захвачен
значение. Только захват по ссылке позволяет изменять переменные в
вызывающая среда.
Additional
Lambda expression формат
Ну, одно практическое применение, которое я обнаружил, — это сокращение кода котельной плиты. Например:
Без лямбды может понадобиться что-то сделать для разных bsize случаев. Конечно, вы могли бы создать функцию, но что, если вы хотите ограничить использование в рамках пользовательской функции Soul? природа лямбда выполняет это требование, и я использую его для этого случая.
Вы можете инициализировать константный член вашего класса с помощью вызова функции, которая устанавливает его значение, возвращая его вывод в качестве выходного параметра.
В следующем примере, чем отличается использование [this] в списке захвата, по сравнению с использованием захвата по ссылке [&] в списке захвата, как показано? Я пробовал оба, и они дают одинаковый результат.
На языке программирования C ++ Стростроп говорит:
Кажется, это подразумевает, что они могут означать одно и то же. Если это так, то зачем нам это?
Решение
[&] захватывает все автоматические переменные, используемые в теле лямбды по ссылке, и текущий объект по ссылке, если существует
Принимая во внимание, что использование [этого] будет захватывать только this указатель.
Это будет отличаться, когда у вас есть автоматические переменные в области, например:
Итак, зачем нам это?
Разрешение захвата [this] аналогично разрешению захвата любого другого указателя.
Почему бы не захватить все автоматические переменные все время? Есть несколько причин, в том числе:
- Инкапсуляция: Иногда вы не хотите, чтобы лямбда была знакома с другими ценностями
- гибкость: Иногда нам нужно скопировать некоторые значения и передать некоторые из них по ссылке
Замечания: Захват всех автоматических переменных с использованием & не вносит дополнительных затрат на производительность, так как компилятор передает только те переменные, которые мы используем внутри лямбда-выражения.
Другие решения
& захватывает все переменные, которые находятся в области видимости по ссылке. Учти это:
[this] не будет захватывать локальные переменные, как будет [&] ,
Единственный способ захватить участников — захват this :
- эксплицитно [this]()
- неявно путем захвата по значению [=]()
- неявно путем захвата по ссылке [&]()
Затем, в зависимости от вашего намерения выразить ограничение захвата, вы можете выбрать между явным или нет, избегая reference захватить (чтобы избежать возможной висячей ссылки) …
С помощью [this] будет захватывать только this , в то время как [&] захваты this а также все локальные переменные из окружающей области.
Вы могли бы использовать [this] если ваше замыкание будет вызываться за пределами охватывающей области, как функция-член, так как все локальные переменные будут уничтожены.
Вы могли бы использовать [&] если ваше замыкание будет вызываться во внешней области видимости, как кусок локального кода, так как локальные переменные все еще будут живы.
создал по руководству окно, нашел где-то вроде как рабочий вариант этого самого прилипания, но скомпилировать не удаётся ругается на локальную переменную в лямбде (в коде указал, где именно). Это первый( и, к сожалению, не последний) раз, когда я в принципе работаю с win32 и сколько я в документацию и гайды не смотрю - толку ноль. помогите пожалуйста
"Enter" - окно перемещается по периметру экрана, "Esc" - остановить перемещение. Как?
Надо написать приложение: • при нажатии клавиши < Enter> главное окно позиционируется в левый.
"Ломается" окно при продолжительном изменении его размеров
Есть простенькая программа, рисующая параболу по трем точкам. Не могу понять почему оно ломается.
WINDOWPOS* wp = (WINDOWPOS*)msg.LParam;//Здесь вижла пишет "на локальную переменную со вложенной функцией нельзя ссылаться внутри тела лямбды, если она не находится в списке записей"
В общем, в конце концов, разобрался, вдруг кому-то потом понадобится:
Как увеличить окно при нажатии "подменю"?
Здравствуйте я пишу крестики нолики на winapi, в принципе саму игру я уже сделал, но через.
Как создать окно без кнопки "закрыть"?
Как создать окно без кнопки "закрыть", но с кнопками "свернуть"/"развернуть" и.
При выборе пункта меню "New" не появляется дочернее окно hChild
Здравствуйте! Вот код для приложения которое создает главное окно с менюшкой, и при выборе.
При запуске программы вылетает окно "Приложение будет закрыто"
HANDLE hThread=0;char *hNewModule;DWORD size;HMODULE hModule; DWORD id; DWORD ByteOfWriten; .
Прозрачное "Безрамочное" окно с видимыми элементами на C++
Пытаюсь сделать прозрачное окно с видимыми элементами на С++. Под таким окном я имею в виду.
Передать значение переменной
Мне нужно узнавать значение переменной в базовом классе, во всех классах наследниках. class.
Передать значение переменной из .cpp в .h
есть переменная, чье значение я хочу передать из .cpp в .h как это лучше сделать? спасибо
Нужно передать значение переменной из класса
Нужна помощь! Как передать значение введённой переменной size в переменную n_size в main? То.
Хуба-Буба, даже с этим проблемы, setw(5) к примеру, принимает нормально и компилируется, мне нужно передать именно переменную, а не константу
Хуба-Буба, error C3493: "n" нельзя передать неявно, поскольку не задан режим передачи по умолчанию
setw(n); n - переменная, вычисляемая по формуле
Объявлял n до цикла, ошибки нет.
"На локальную переменную со вложенной функцией нельзя ссылаться внутри тела лямбды, если она не находится в списке записей"
Скиньте Ваш рабочий код, чтобы понять конечную цель и исходные данные. Если Вы работаете с русским текстом - могут быть дополнительные фишки при использовании setw.
int count = vct.size(); double count_sqrt = sqrt(count); double celaya; double drobnoe = modf(count_sqrt, &celaya);
и ответте на вопрос что это вам даст celaya если в файле 9 цифр и там есть предположим цифра 12345678 ?
Encrypted1010, в итоге Вам нужно получить квадратную матрицу из тех данных, которые содержатся в файле? Или что? Пример: файл содержит в столбик цифры: 1 2 3 4 5 6 7 8 9
Результат должен быть таким:
1 2 3
4 5 6
7 8 9
Encrypted1010, Мы пока тоже ничего не понимаем, что во первых находится в файле, и что вы хотите в результате получить оттуда в вектор. И как при этом переменные count_sqrt celaya drobnoe сочетаются применив при использовании regex rgx< "[-[:digit:]]+" >;
к своему вопросу хочу сказать что цифра 12345678 никакого отношения к результату celaya не имеет, результат в вашем коде будет корень из 9 а это 3 - т.е корень из длины вектора - которую вы хотели привязать к setw(), а по логике вернее всего ожидали рассчитать длину длиннешей цифры в файле, чтобы потом адекватно отобразить в виде таблицы
Хуба-Буба, error C3493: "n" нельзя передать неявно, поскольку не задан режим передачи по умолчанию setw(n); n - переменная, вычисляемая по формуле
Этот вопрос не имеет никакого отношения к setw вообще, даже отдаленно. Никаких особенностей у setw нет - передавайте все, что угодно, хоть переменную, хоть константу.
Ваш вопрос - про лямбды. Переменные извне в лямбду надо как-то передавать: либо через параметры, либо через захват. Вы этого не сделали.
TheCalligrapher, как именно передавать?
Этот вопрос не имеет никакого отношения к setw вообще, даже отдаленно. Никаких особенностей у setw нет - передавайте все, что угодно, хоть переменную, хоть константу.
Теперь Encrypted1010 - похоже, что Вы собрали код из разных источников в единое целое. Поэтому еще вопрос: у Вас какие требования к разработке программы? Нужно ли обязательно использовать лямбда-выражения, векторы?
Если Вас полностью устраивает текущая работа программы - то разделяйте элементы матрицы табуляцией. Если же работа программы Вас не устраивает(а работает она неправильно, во всяком случае на моих тестах) - то конкретизируйте проблему и давайте полное описание что нужно и что допускается/не допускается использовать при решении.
Чем больше и точней будет информации на входе - тем качественней выходной результат. И сами будете задачу знать хорошо и нам будет проще :-)
Читайте также: