Ci sono un paio di cose da chiarire riguardo alla tua domanda. Il primo dei quali è cos'è un lambda?
Un'espressione lambda è un'espressione semplice da cui il compilatore genererà un tipo univoco che non può essere denominato e allo stesso tempo genererà un'istanza del tipo. Quando si scrive: [](int i) { std::cout << i; }
il compilatore genera un tipo per te, che è più o meno:
struct __lambda_unique_name {
void operator()(int i) const { std::cout << i; }
};
Come si può vedere, è non una funzione, ma un tipo che implementa operator()
in funzione const
membro. Se lambda ha effettuato alcuna cattura, il compilatore genererebbe il codice per acquisire il valore/i riferimenti.
Come caso angolo, per lambda come sopra, dove non c'è stato essere catturato, il linguaggio consente una conversione dal tipo lambda a un puntatore a funzionare con la firma del operator()
(meno la parte this
) , in modo che il lambda sopra può essere implicitamente convertito in un puntatore a funzione di prendere int
e rinviare nulla:
void (*f)(int) = [](int i) { std::cout << i; }
Ora che le basi sono stati esposti, nel codice si dispone di questo lambda:
auto f = [x,y](double (func)(int)) -> double {func(0); return 0.0;};
Le regole per i parametri alle funzioni (che si applicano anche ai lambdas) determinano che un argomento non può essere di tipo funzione, quindi l'argomento del lambda decade a un puntatore alla funzione (nello stesso modo in cui un argomento di tipo array decade ad un tipo di puntatore):
auto f = [x,y](double (*func)(int)) -> double {func(0); return 0.0;};
in un momento successivo si sta tentando di passare un lambda che ha una cattura come argomento. Poiché esiste un'acquisizione, la regola speciale non si applica e la lambda non è convertibile in un puntatore alla funzione che genera l'errore del compilatore che vedi.
Nello standard corrente è possibile scegliere tra due metodi. È possibile utilizzare tipo-cancellazione per rimuovere l'esatto tipo di entità richiamabile dalla firma:
auto f = [x,y](std::function<double(int)> func) -> double {func(0); return 0.0;};
Perché un std::function<double(int)>
può essere inizializzato con qualsiasi callable entità con l'indicatore appropriato, questo accetterà la lambda nella codice sottostante, al costo della cancellazione del tipo che di solito implica un'allocazione dinamica e un dispacciamento dinamico.
In alternativa, è possibile eliminare lo zucchero sintattico e arrotolare manualmente il primo equivalente lambda, ma renderlo generico. In questo caso, in cui il lambda è semplice questo potrebbe essere un'opzione valida:
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;});
Infine, se siete abbastanza pazienti, è possibile attendere per C++ 14, in cui (molto probabilmente, non è ancora stato ratificato) ci sarà il supporto per lambda polimorfici che semplificano la creazione della classe di cui sopra:
auto f = [](auto fn) { fn(0.0); return 0.0; } // unrolls to 'mylambda' above
Catturare lambda non è convertibile in puntatori di funzione –
perché non un 'constexpr'? 'auto' è una funzionalità in fase di compilazione comunque ... – user2485710
@AndyProwl Cosa? Nessuna risposta dettagliata da te entro 10 minuti? Dai, ci fai lavorare troppo duramente qui, e non hai nemmeno una copia per il giorno ;-) – TemplateRex