Próbowałem stworzyć wektor lambda, ale nie udało mi się:
auto ignore = [&]() { return 10; }; //1
std::vector<decltype(ignore)> v; //2
v.push_back([&]() { return 100; }); //3
Do linii nr 2 kompiluje się dobrze . Ale wiersz # 3 podaje błąd kompilacji :
błąd: brak funkcji dopasowującej dla wywołania 'std :: vector <main () :: <lambda () >> :: push_back (main () :: <lambda ()>)'
Nie chcę wektora wskaźników funkcji ani wektora obiektów funkcji. Jednak wektor obiektów funkcyjnych, które hermetyzują prawdziwe wyrażenia lambda, byłby dla mnie odpowiedni. czy to możliwe?
Odpowiedzi:
Każda lambda ma inny typ - nawet jeśli ma ten sam podpis. Musisz użyć kontenera hermetyzującego w czasie wykonywania, na przykład
std::function
jeśli chcesz zrobić coś takiego.na przykład:
std::vector<std::function<int()>> functors; functors.push_back([&] { return 100; }); functors.push_back([&] { return 10; });
źródło
std::function<int()
, czy mógłbym używać różnych prototypów funkcji?vector
magazyn zarównostd::function
istd::string
?” Odpowiedź jest taka sama: nie, ponieważ nie jest to zamierzone zastosowanie. Możesz użyć klasy w stylu `` wariant '', aby wykonać wystarczające wymazanie typu, aby umieścić różne rzeczy w kontenerze, jednocześnie włączając metodę dla użytkownika, aby określić `` prawdziwy '' typ i tym samym wybrać, co zrobić z (np. Jak wywołać) każdy element ... ale znowu, po co iść do takich długości? Czy jest jakieś prawdziwe uzasadnienie?Wszystkie wyrażenia lambda mają inny typ, nawet jeśli są identyczne znak po znaku . Wsuwasz do wektora lambdę innego typu (ponieważ jest to inne wyrażenie), a to oczywiście nie zadziała.
Jednym z rozwiązań jest utworzenie wektora
std::function<int()>
zamiast.auto ignore = [&]() { return 10; }; std::vector<std::function<int()>> v; v.push_back(ignore); v.push_back([&]() { return 100; });
Z drugiej strony, nie jest dobrym pomysłem używanie go,
[&]
gdy niczego nie przechwytujesz.źródło
()
lambd, które nie przyjmują żadnych argumentów.Chociaż to, co powiedzieli inni, jest istotne, nadal można zadeklarować i użyć wektora lambda, chociaż nie jest to zbyt przydatne:
auto lambda = [] { return 10; }; std::vector<decltype(lambda)> vec; vec.push_back(lambda);
Więc możesz tam przechowywać dowolną liczbę lambd, o ile jest to kopia / przeniesienie
lambda
!źródło
Jeśli twoja lambda jest bezstanowa, tj.
[](...){...}
C ++ 11 pozwala jej zdegradować ją do wskaźnika funkcji. Teoretycznie kompilator zgodny z C ++ 11 byłby w stanie skompilować to:auto ignore = []() { return 10; }; //1 note misssing & in []! std::vector<int (*)()> v; //2 v.push_back([]() { return 100; }); //3
źródło
auto ignore = *[] { return 10; };
zrobiłobyignore
toint(*)()
.explicit
, wyłuskiwanie wyrażenia lambda jest poprawne i usuwa odniesienie do wskaźnika wynikającego z konwersji. Następnie używającauto
rozpadów, które odwołują się z powrotem do wskaźnika. (Używającauto&
lubauto&&
zachowałby odniesienie.)()
zamierzone czy przypadkowe?Można by skorzystać z funkcji generującej lambdę (zaktualizowanej poprawką sugerowaną przez Nawaza):
#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++; } }
Ale myślę, że w zasadzie stworzyłeś swoją własną klasę w tym momencie. W przeciwnym razie, jeśli lambdy mają zupełnie inne caputres / args itp., Prawdopodobnie będziesz musiał użyć krotki.
źródło
lambda_gen
która z kolei może być samą lambdą. Jednakauto a = lambda_gen(1);
wykonuje niepotrzebne wezwanie, którego można uniknąć, jeśli to napiszemydecltype(lambda_gen(1))
.decltype
jest nieocenione , więc połączenie nie jest faktycznie wykonywane. To samo dotyczysizeof
również. Ponadto ten kod nie będzie działał w C ++ 11, nawet jeśli dodasz końcowy typ powrotu !!Każda lambda jest innego typu. Musisz użyć
std::tuple
zamiaststd::vector
.źródło