2013-06-28 15 views
5

Chcę uchwycić „odniesienia” do lambda, i pomyślałem, że wskaźnik funkcji by rade, jak w:Jak utworzyć "odniesienie" do lambda?

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

ale mam cannot convert from main::lambda<......> to int(_cdecl *)(int).

Jaki jest właściwy sposób wskazywania lambda?

+3

Lambda może zostać przekonwertowana na wskaźnik funkcji, jeśli niczego nie przechwytuje. – jrok

+0

Fajnie, masz rację. Dobrze wiedzieć, dzięki. – sircodesalot

+0

To jest prawie duplikat http://stackoverflow.com/questions/2067988/recursive-lambda-functions-in-c0x – doctorlove

Odpowiedz

6

Ponieważ lambda nie jest bezstanowa, nie można jej przekonwertować na wskaźnik funkcji. Zamiast tego użyj std::function.

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

To ma nietrywialne koszty ogólne, jako ostrzeżenie, w porównaniu do "surowych" lambd. Każde wywołanie jest mniej więcej równoważne wywołaniu metody "wirtualnej". To nie jest takie złe, ale w porównaniu z pracą wykonywaną w trakcie rozmowy jest znaczące. – Yakk

+0

@Yakk Tak, płacisz koszt usunięcia 'std :: function'; Właśnie szukałem tej odpowiedzi sprzed kilku tygodni, aby linkować do: – Praetorian

+0

Co to znaczy "niestanowić"? Ponadto, co to są koszty ogólne? – sircodesalot

5

Byłoby najbliżej tego, co już masz:

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

normalnie można też użyć auto, ale w tym przypadku to nie działa, ponieważ funkcja jest rekurencyjna.

+1

'auto' nie działa, zobacz powiązane pytanie. –

+0

@JesseDobry: dobry punkt - dzięki. –

5

Masz już dobre odpowiedzi. Poniższa jest tylko ciekawostką, ale nie sugerowałbym, żebyś z niej korzystał.

Jak powiedziała inna odpowiedź, lambda factorial próbuje się uchwycić i dlatego nie jest bezpaństwowcem. Dlatego nie można go przekonwertować na wskaźnik funkcji.

lambdas nie trzeba uchwycić globalne lub static przedmiotów, więc jeśli zrobisz factorial zmienną globalną lub static wtedy nie trzeba go uchwycić i to działa prawidłowo (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'; 
    } 

można również utworzyć fabrykę takiego:

#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'; 
    } 

Jeśli chcesz zaciemniać nawet więcej :-) następnie wyeliminować 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; 
    } 
Powiązane problemy