Odkryłem, że lvalue
zamknięcia lambda zawsze można przekazać jako rvalue
parametry funkcji.
Zobacz następującą prostą demonstrację.
#include <iostream>
#include <functional>
using namespace std;
void foo(std::function<void()>&& t)
{
}
int main()
{
// Case 1: passing a `lvalue` closure
auto fn1 = []{};
foo(fn1); // works
// Case 2: passing a `lvalue` function object
std::function<void()> fn2 = []{};
foo(fn2); // compile error
return 0;
}
Przypadek 2 to standardowe zachowanie (właśnie użyłem std::function
do celów demonstracyjnych, ale każdy inny typ zachowałby się tak samo).
Jak i dlaczego działa przypadek 1? Jaki jest stan fn1
zamknięcia po zwróceniu funkcji?
fn1
domyślnie jest konwertowany nastd::function
infoo(fn1)
. Ta tymczasowa funkcja jest wtedy wartością rvalue.std::function
można wywnioskować argumentów z lambda”. Twój program nie próbuje wywnioskować argumentów szablonustd::function
, więc nie ma problemu z niejawną konwersją.std::function
ma nieprecyzyjny konstruktor, który akceptuje zamknięcia lambda, więc zachodzi niejawna konwersja. Ale w okolicznościach połączonego pytaniastd::function
nie można wywnioskować z wystąpienia lambda typu szablonu . (Na przykładstd::function<void()>
można skonstruować z[](){return 5;}
tego, że ma on nieważny typ zwrotu.Odpowiedzi:
Wywołanie
foo
wymaga wystąpieniastd::function<void()>
tego powiązania z odwołaniem do wartości .std::function<void()>
można zbudować z dowolnego obiektu, który można wywołać, który jest zgodny zvoid()
podpisem.Po pierwsze,
std::function<void()>
budowany jest obiekt tymczasowy[]{}
. Użyto konstruktora tutaj # 5 , który kopiuje zamknięcie dostd::function
instancji:Następnie
function
instancja tymczasowa jest powiązana z odwołaniem do wartości.To samo co poprzednio, ponieważ zostało skopiowane do
std::function
instancji. Oryginalne zamknięcie pozostaje nienaruszone.źródło
Lambda nie jest
std::function
. Odwołanie nie wiąże się bezpośrednio .Przypadek 1 działa, ponieważ lambda można zamienić na
std::function
s. Oznacza to, że tymczasowestd::function
jest zmaterializowane przez kopiowaniefn1
. Wspomniany tymczasowy może być powiązany z odwołaniem do wartości, a zatem argument pasuje do parametru.A kopiowanie jest również powodem, dla
fn1
którego nic nie dzieje się w ogólefoo
.źródło
fn1
jest bezpaństwowcem, ponieważ niczego nie chwyta.Działa, ponieważ argument jest innego typu niż typ, do którego odwołuje się wartość. Ze względu na inny typ rozważane są niejawne konwersje. Ponieważ lambda jest wywoływalna dla argumentów tego
std::function
, jest domyślnie konwertowalna na nią za pomocą konstruktora konwertującego szablonstd::function
. Wynikiem konwersji jest prvalue, a zatem można ją powiązać z referencją wartości.źródło