2012-09-28 12 views
28

Czytałem o zamknięciach w sieci. Zastanawiam się, czy C++ ma wbudowaną możliwość zamykania lub czy istnieje sposób, w jaki możemy zaimplementować zamknięcia w C++?Czy mamy zamknięcia w C++?

+3

Oprócz odpowiedzi poniżej, sprawdź również http://en.cppreference.com/w/cpp/language/lambda, aby uzyskać więcej informacji na temat strony referencyjnej. –

+0

Podobno wiele osób wciąż miesza anonimowe funkcje z zamknięciami. Wciąż nie jest dla mnie jasne, czy C++ 11 rzeczywiście obsługuje zamknięcia, czy tylko anonimowe funkcje ("lambdas"). Nie oczekuję, że C++ będzie obsługiwać rzeczywiste zamknięcie w takim samym sensie, jak w JavaScript, Pythonie, Scali i innych, może to być bardzo zaskakujące. – dividebyzero

+1

Udowadniając, że się mylę, tak, przechwytuje zmienne w kontekście, przez kopiowanie, a nawet przez odniesienie, najwyraźniej jedynym dziwactwem jest to, że nie ma zbierania śmieci ... Nadal chciałbym lepiej zrozumieć, jak to wszystko działa w praktyce http: // pl.cppreference.com/w/cpp/language/lambda – dividebyzero

Odpowiedz

6

Tak, C++ 11 ma zamknięcia nazwie lambdas.

W C++ 03 nie ma wbudowanej obsługi lambd, ale istnieje implementacja Boost.Lambda.

5

Podejrzewam, że to zależy od tego, co rozumiesz przez zamknięcie. Znaczenie, jakie mam zawsze używane, oznacza, że ​​jakiś rodzaj zbierania śmieci (chociaż myślę, że można go zaimplementować za pomocą liczenia odwołań); w przeciwieństwie do lambdów w innych językach , które przechwytują referencje i utrzymują przy życiu obiekt odniesienia, którym jest obiekt odniesienia, lub przechwytują wartość, lub obiekt, którego dotyczy, jest utrzymywany przy życiu (i odniesienie może łatwo zwisać).

12

Jeśli rozumiesz zamknięcie jako odniesienie do funkcji, która ma wbudowany, trwały, ukryte i nierozerwalna kontekst (pamięć, państwa), wtedy tak:

class add_offset { 
private: 
    int offset; 
public: 
    add_offset(int _offset) : offset(_offset) {} 
    int operator() (int x) { return x + offset; } 
} 

// make a closure 
add_offset my_add_3_closure(3); 

// use cloure 
int x = 4; 
int y = my_add_3_closure(x); 
std::cout << y << std::endl; 

następny zmienia swój stan:

class summer 
{ 
private: 
    int sum; 
public: 
    summer() : sum(0) {} 
    int operator() (int x) { return sum += x; } 
} 

// make a closure 
summer adder; 
// use closure 
adder(3); 
adder(4); 
std::cout << adder(0) << std::endl; 

Stan wewnętrzny nie może być odwoływany (dostęp) z zewnątrz.

W zależności od tego, jak to zdefiniujesz, zamknięcie może zawierać odwołanie do więcej niż jednej funkcji lub dwie zamknięcia mogą współdzielić ten sam kontekst, tj. Dwie funkcje mogą współdzielić ten sam stały, ..., stan.

Zamknięcie oznacza niezawierające zmiennych wolnych - jest porównywalne z klasą zawierającą tylko prywatne atrybuty i tylko publiczne metody (metody).

+3

Zachowanie jest podobne do zamknięcia, ale nie powiedziałbym, że jest zamknięcie. – Setepenre

+0

@Stepenre jaka byłaby różnica? – Zrin

+2

To prawie nie wygląda na zamknięcie, to, co tu masz, to tylko obiekt trzymający stan zmodyfikowany przez metodę, plus trochę cukru syntaktycznego, ponieważ jest to "operator()" zamiast jakiejkolwiek innej metody. Niech zwróci wartość lambda zależną od stanu lub parametru metody, a następnie rozmawiamy. – dividebyzero

6

Tak, to pokazuje, jak można zaimplementować funkcję ze stanem bez użycia funktora.

#include <iostream> 
#include <functional> 


std::function<int()> make_my_closure(int x){ 
    return [x]() mutable { 
     ++x; 
     return x; 
    }; 
} 

int main() 
{ 
    auto my_f = make_my_closure(10); 

    std::cout << my_f() << std::endl; // 11 
    std::cout << my_f() << std::endl; // 12 
    std::cout << my_f() << std::endl; // 13 

    auto my_f1 = make_my_closure(1); 

    std::cout << my_f1() << std::endl; // 2 
    std::cout << my_f1() << std::endl; // 3 
    std::cout << my_f1() << std::endl; // 4 

    std::cout << my_f() << std::endl; // 14 
} 

Zapomniałem zmiennego słowa kluczowego, które wprowadziło niezdefiniowane zachowanie (wersja klangowa zwróciła wartość śmieci). Zgodnie z wdrożeniem, zamknięcie działa poprawnie (na GCC i klang)

+0

Aby być naprawdę pewnym, byłoby miło zobaczyć, co stanie się, jeśli uruchomisz 'my_f()' ponownie po 'my_f1()', ponieważ może to być wciąż ta sama zmienna, która została bezpośrednio przypisana do wywołania 'make_my_closure ' '. – dividebyzero

+1

'x' jest wartością tymczasową w' make_my_closure'. Więc IMO nie miałoby sensu. Dodałem sprawę, o którą prosiłeś. Które zachowują się zgodnie z oczekiwaniami – Setepenre

Powiązane problemy