web-dev-qa-db-fra.com

Avons-nous des fermetures en C ++?

Je lisais des fermetures sur le net. Je me demandais si C++ avait une fonction intégrée pour les fermetures ou s'il y avait un moyen de mettre en œuvre des fermetures en C++?

47
Parvinder Singh
39
Apeirogon Prime

Si vous comprenez la fermeture comme une référence à une fonction qui a un contexte incorporé, persistant, caché et indissociable (mémoire, état), alors oui:

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;

le suivant modifie son état:

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;

L'état intérieur ne peut pas être référencé (accessible) de l'extérieur.

Selon la façon dont vous le définissez, une fermeture peut contenir une référence à plusieurs fonctions ou, deux fermetures peuvent partager le même contexte, c'est-à-dire que deux fonctions peuvent partager le même état persistant, ...,.

La fermeture signifie ne pas contenir de variables libres - elle est comparable à une classe avec uniquement des attributs privés et uniquement des méthodes publiques.

18
Zrin

Oui, cela montre comment vous pouvez implémenter une fonction avec un état sans utiliser de foncteur.

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

J'ai oublié le mot-clé mutable qui a introduit un comportement indéfini (la version clang renvoyait une valeur poubelle). Telle que mise en œuvre, la fermeture fonctionne bien (sur GCC et clang)

14
Setepenre

Oui, C++ 11 a des fermetures nommées lambdas .

En C++ 03, il n'y a pas de support intégré pour les lambdas, mais il y a l'implémentation Boost.Lambda .

7
Rost

Je soupçonne que cela dépend de ce que vous entendez par fermeture. Le sens que j'ai toujours utilisé implique un ramasse-miettes (bien que je pense qu'il pourrait être implémenté en utilisant le comptage de références); contrairement aux lambdas dans d'autres langages, qui capturent les références et maintiennent l'objet référencé vivant, les lambdas C++ capturent une valeur, ou l'objet référencé est pas maintenu vivant (et la référence peut facilement pendre).

7
James Kanze