2013-06-28 17 views
5

Voglio catturare un 'riferimento' per un lambda, e ho pensato che un puntatore a funzione farebbe il trucco, come in:Come creo un "riferimento" a un lambda?

int (*factorial)(int) = [&](int x){ 
    return (x < 2) 
     ? 1 
     : x * factorial(x - 1); 
}; 

ma ho cannot convert from main::lambda<......> to int(_cdecl *)(int).

Qual è il modo corretto di indicare un lambda, quindi?

+3

Un lambda può essere convertito in un puntatore a funzione se non cattura nulla. – jrok

+0

Cool, hai ragione. Buono a sapersi, grazie. – sircodesalot

+0

Questo è quasi un duplicato di http://stackoverflow.com/questions/2067988/recursive-lambda-functions-in-c0x – doctorlove

risposta

6

Poiché lambda non è stateless, non può essere convertito in un puntatore di funzione. Utilizzare invece std::function.

std::function<int(int)> factorial = [&](int x){ 
    return (x < 2) 
     ? 1 
     : x * factorial(x - 1); 
}; 
+1

Questo ha costi generali non banali, come avvertimento, rispetto ai lambda "grezzi". Ogni chiamata equivale approssimativamente a chiamare un metodo 'virtuale'. Non è così male, ma rispetto al lavoro svolto nella chiamata, è significativo. – Yakk

+0

@Yakk Sì, si paga il costo della cancellazione del tipo 'std :: function'; Stavo solo cercando la risposta di qualche settimana fa per collegarmi a :) – Praetorian

+0

Cosa significa "non apolidi"? Inoltre, @Yakk quali sono i costi generali? – sircodesalot

5

Questo sarebbe più vicino a quello che hai già:

std::function<int (int)> factorial = [&](int x){ 
    return (x < 2) 
     ? 1 
     : x * factorial(x - 1); 
}; 

normalmente si potrebbe anche usare auto, ma in questo caso non funziona perché la funzione è ricorsiva.

+1

"auto" non funziona, vedere la domanda collegata. –

+0

@JesseGood: buon punto - grazie. –

5

Hai già buone risposte. Quello che segue è solo una curiosità ma non ti suggerirei di usarlo.

Come detto da altri, la lambda factorial tenta di catturare se stessa e quindi non è apolidi. Pertanto, non è convertibile in un puntatore a funzione.

Lambda non hanno bisogno di catturare gli oggetti globali o static, quindi se si effettua factorial una variabile globale o static allora non c'è bisogno di catturare e questo funziona bene (GCC 4.7.2)

#include <iostream> 

    typedef int (*function)(int); 

    int main() { 
     static function factorial = [](int x){ 
      return (x < 2) ? 1 : x * factorial(x - 1); 
     }; 
     std::cout << factorial(5) << '\n'; 
    } 

È inoltre possibile creare una fabbrica come questa:

#include <iostream> 

    typedef int (*function)(int); 

    function make_factorial() { 
     static function factorial = [](int x){ 
      return (x < 2) ? 1 : x * factorial(x - 1); 
     }; 
     return factorial; 
    } 

    int main() { 
     auto factorial = make_factorial(); 
     std::cout << factorial(5) << '\n'; 
    } 

Se si vuole offuscare ancora di più :-) quindi eliminare il typedef:

// This is a function returning a pointer to a function taking an int and returning an int. 
    int (*(make_factorial)())(int) { 
     static int (*factorial)(int) = [](int x){ 
      return (x < 2) ? 1 : x * factorial(x - 1); 
     }; 
     return factorial; 
    } 
Problemi correlati