Я пытался создать вектор лямбда, но не смог:
auto ignore = [&]() { return 10; }; //1
std::vector<decltype(ignore)> v; //2
v.push_back([&]() { return 100; }); //3
До строки №2 компилируется нормально . Но строка №3 дает ошибку компиляции :
ошибка: нет соответствующей функции для вызова 'std :: vector <main () :: <lambda () >> :: push_back (main () :: <lambda ()>)'
Мне не нужен вектор указателей на функции или вектор объектов функций. Однако вектор функциональных объектов, которые инкапсулируют реальные лямбда-выражения, подойдет мне. Это возможно?
Ответы:
Каждая лямбда имеет разный тип, даже если у них одна и та же сигнатура. Вы должны использовать инкапсулирующий контейнер времени выполнения, например,
std::function
если вы хотите сделать что-то подобное.например:
std::vector<std::function<int()>> functors; functors.push_back([&] { return 100; }); functors.push_back([&] { return 10; });
источник
std::function<int()
, могу ли я использовать разные прототипы функций?vector
хранилище иstd::function
иstd::string
?» И ответ тот же: нет, потому что это не по назначению. Вы можете использовать класс в стиле «вариант» для выполнения стирания типа, достаточного для помещения несопоставимых вещей в контейнер, в то же время включая метод, позволяющий пользователю определить «настоящий» тип и, следовательно, выбрать, что с ним делать (например, как вызвать) каждый элемент ... но опять же, зачем так далеко? Есть ли какое-нибудь реальное объяснение?Все лямбда-выражения имеют разный тип, даже если они посимвольно идентичны . Вы вставляете лямбду другого типа (потому что это другое выражение) в вектор, и это явно не сработает.
Одно из решений -
std::function<int()>
вместо этого создать вектор .auto ignore = [&]() { return 10; }; std::vector<std::function<int()>> v; v.push_back(ignore); v.push_back([&]() { return 100; });
С другой стороны, это не лучшая идея,
[&]
если вы ничего не захватываете.источник
()
лямбды, которые не принимают аргументов.Хотя то, что другие сказали, актуально, все еще можно объявить и использовать вектор лямбда, хотя это не очень полезно:
auto lambda = [] { return 10; }; std::vector<decltype(lambda)> vec; vec.push_back(lambda);
Таким образом, вы можете хранить там любое количество лямбд, если это копия / перемещение
lambda
!источник
Если ваша лямбда не имеет состояния, т. Е.
[](...){...}
C ++ 11 позволяет ей преобразоваться в указатель на функцию. Теоретически компилятор, совместимый с C ++ 11, сможет это скомпилировать:auto ignore = []() { return 10; }; //1 note misssing & in []! std::vector<int (*)()> v; //2 v.push_back([]() { return 100; }); //3
источник
auto ignore = *[] { return 10; };
сделает .ignore
int(*)()
explicit
, разыменование лямбда-выражения является допустимым и разыменовывает указатель, полученный в результате преобразования. Затем с помощьюauto
распада этой ссылки обратно в указатель. (Используяauto&
илиauto&&
сохранил бы ссылку.)()
намеренным или случайным?Вы можете использовать функцию генерации лямбда (обновлено исправлением, предложенным Nawaz):
#include <vector> #include <iostream> int main() { auto lambda_gen = [] (int i) {return [i](int x){ return i*x;};} ; using my_lambda = decltype(lambda_gen(1)); std::vector<my_lambda> vec; for(int i = 0; i < 10; i++) vec.push_back(lambda_gen(i)); int i = 0; for (auto& lambda : vec){ std::cout << lambda(i) << std::endl; i++; } }
Но я думаю, что на этом этапе вы в основном создали свой собственный класс. В противном случае, если лямбды имеют совершенно разные caputres / args и т. Д., Вам, вероятно, придется использовать кортеж.
источник
lambda_gen
которая, в свою очередь, может быть лямбдой. Однакоauto a = lambda_gen(1);
делает ненужный вызов, которого можно избежать, если мы напишем этоdecltype(lambda_gen(1))
.decltype
находится внутри, не оценивается , поэтому вызов на самом деле не производится. То же самое и сsizeof
. Кроме того, этот код не будет работать в C ++ 11, даже если вы добавите конечный возвращаемый тип !!Каждая лямбда - это отдельный тип. Вы должны использовать
std::tuple
вместоstd::vector
.источник