Jest kilka rzeczy do wyjaśnienia w odniesieniu do pytania. Pierwszym z nich jest czym jest lambda?
Wyrażenie lambda prosty ekspresji, z którego kompilator generuje unikalny rodzaj, który nie może być nazwany i jednocześnie generuje wystąpienie typu. Kiedy piszesz: [](int i) { std::cout << i; }
kompilator wygeneruje dla ciebie typ, który jest w przybliżeniu:
struct __lambda_unique_name {
void operator()(int i) const { std::cout << i; }
};
Jak widać, jest to nie funkcją, ale to typ, który implementuje operator()
jako funkcja const
członkowskim. Jeśli lambda zrobiła jakiekolwiek przechwytywanie, kompilator wygenerowałby kod do przechwytywania wartości/referencji.
Jako narożna obudowa, dla lambdas takich jak powyższe, gdzie nie ma przechwyconego stanu, język pozwala na konwersję z typu lambda na wskaźnik działający z podpisem operator()
(minus część this
) , więc lambda powyżej można niejawnie konwertowane do wskaźnika funkcjonować biorąc int
i powrocie nic:
void (*f)(int) = [](int i) { std::cout << i; }
Skoro podstawy zostały określone w kodzie masz ten lambda:
auto f = [x,y](double (func)(int)) -> double {func(0); return 0.0;};
Reguły dla parametrów do funkcji (które również dotyczą lambdas) określają, że argument nie może być typu , funkcja, więc argument do lambda rozpada się na wskaźnik do funkcji (w ten sam sposób, co argument tablicy typów rozpady do typu wskaźnika):
auto f = [x,y](double (*func)(int)) -> double {func(0); return 0.0;};
W późniejszym momencie próbujesz przekazać lambdę, która przechwytuje jako argument. Ponieważ istnieje przechwytywanie, specjalna reguła nie ma zastosowania, a lambda nie jest wymienna na wskaźnik funkcji, który powoduje pojawienie się błędu kompilatora.
W obecnym standardzie można przejść na jeden z dwóch sposobów. Można użyć typu skasowaniu usunąć dokładny typ na żądanie podmiotu z podpisem:
auto f = [x,y](std::function<double(int)> func) -> double {func(0); return 0.0;};
Ponieważ std::function<double(int)>
można zainicjować z dowolnego na żądanie podmiotu z odpowiednim podpisem, to zaakceptuje lambdy w kod poniżej, kosztem usunięcia typu, który zwykle oznacza dynamiczną alokację i dynamiczną wysyłkę.
Alternatywnie możesz upuścić cukier syntaktyczny i rzucić pierwszy równoważnik lambda ręcznie, ale spraw, aby był ogólny. W tym przypadku, gdzie lambda jest prosty to może być ważna opcja:
struct mylambda {
template <typename F>
double operator()(F fn) const {
fn(0); return 0.0;
}
} f;
// then use the non-lambda as you tried:
f([x](int i) -> double {return 0.0;});
Wreszcie, jeśli jesteś wystarczająco cierpliwy, można czekać na C++ 14, gdzie (najprawdopodobniej, że nie został jeszcze ratyfikowana) nie będzie wsparcie dla polimorficznych lambdas który uprości tworzenie powyższej klasy:
auto f = [](auto fn) { fn(0.0); return 0.0; } // unrolls to 'mylambda' above
Przechwytywanie lambdas nie są zamienne do wskaźników funkcji –
dlaczego nie "constexpr"? 'auto' jest tak czy inaczej funkcją kompilacji ... – user2485710
@AndyProwl What? Brak szczegółowej odpowiedzi od Ciebie w ciągu 10 minut? Daj spokój, sprawiasz, że pracujemy tutaj zbyt ciężko, a ty nawet nie przepadłeś za dnia ;-) – TemplateRex