web-dev-qa-db-fra.com

Utilisation et syntaxe de std :: function

Il me faut utiliser std::function mais je ne sais pas ce que signifie la syntaxe suivante.

std::function<void()> f_name = []() { FNAME(); };

Quel est l'objectif de l'utilisation de std::function? Est-ce pour faire un pointeur sur une fonction?

23
user2982229

std::function Est un objet d'effacement de type. Cela signifie qu'il efface les détails de la façon dont certaines opérations se produisent et leur fournit une interface d'exécution uniforme. Pour std::function, Le principal1 les opérations sont copier/déplacer, détruire et "invoquer" avec operator() - la "fonction comme opérateur d'appel".

Dans un anglais moins abstrus, cela signifie que std::function Peut contenir presque n'importe quel objet qui agit comme un pointeur de fonction dans la façon dont vous l'appelez.

La signature qu'il prend en charge va à l'intérieur des crochets: std::function<void()> ne prend aucun argument et ne renvoie rien. std::function< double( int, int ) > prend deux arguments int et retourne double. En général, std::function Prend en charge le stockage de tout objet de type fonction dont les arguments peuvent être convertis à partir de sa liste d'arguments et dont la valeur de retour peut être convertie à sa valeur de retour.

Il est important de savoir que std::function Et les lambdas sont des bêtes différentes, si elles sont compatibles.

La partie suivante de la ligne est un lambda. Il s'agit d'une nouvelle syntaxe en C++ 11 pour ajouter la possibilité d'écrire des objets fonctionnels simples - des objets qui peuvent être invoqués avec (). Ces objets peuvent être effacés de type et stockés dans un std::function Au prix d'une surcharge de temps d'exécution.

[](){ code } en particulier est un lambda vraiment simple. Cela correspond à ceci:

struct some_anonymous_type {
  some_anonymous_type() {}
  void operator()const{
    code
  }
};

une instance du type de pseudo-fonction simple ci-dessus. Une classe réelle comme la précédente est "inventée" par le compilateur, avec un nom unique défini par l'implémentation (comprenant souvent des symboles qu'aucun type défini par l'utilisateur ne peut contenir) (je ne sais pas s'il est possible que vous puissiez suivre la norme sans inventer une telle classe, mais tous les compilateurs que je connais créent en fait la classe).

La syntaxe lambda complète ressemble à ceci:

[ capture_list ]( argument_list )
-> return_type optional_mutable
{
  code
}

mais de nombreuses parties peuvent être omises ou laissées vides. La capture_list correspond à la fois au constructeur du type anonyme résultant et à ses variables membres, l'argument_list aux arguments de la operator() et le type de retour au type de retour. Le constructeur de l'instance lambda est également appelé par magie lorsque l'instance est créée avec la capture_list.

[ capture_list ]( argument_list ) -> return_type { code }

devient essentiellement

struct some_anonymous_type {
  // capture_list turned into member variables
  some_anonymous_type( /* capture_list turned into arguments */ ):
    /* member variables initialized */
  {}
  return_type operator()( argument_list ) const {
    code
  }
};

1 De plus, RTTI est stocké (typeid), et l'opération de restauration du type d'origine est incluse.

58

Brisons la ligne:

std :: function

Il s'agit d'une déclaration pour une fonction ne prenant aucun paramètre et ne retournant aucune valeur. Si la fonction renvoyait un int, cela ressemblerait à ceci:

std::function<int()>

De même, s'il a également pris un paramètre int:

std::function<int(int)>

Je soupçonne que votre confusion principale est la partie suivante.

[]() { FNAME(); };

La partie [] Est appelée clause de capture. Ici, vous placez des variables qui sont locales à la déclaration de votre lambda, et que vous voulez être disponible within la fonction lambda elle-même. Cela veut dire "je ne veux rien capturer". Si c'était dans une définition de classe et que vous vouliez que la classe soit disponible pour le lambda, vous pourriez faire:

[this]() { FNAME(); };

La partie suivante, est les paramètres passés au lambda, exactement les mêmes que si c'était une fonction régulière. Comme mentionné précédemment, std::function<void()> est une signature pointant vers une méthode qui ne prend aucun paramètre, elle est donc également vide.

Le reste est le corps du lambda lui-même, comme s'il s'agissait d'une fonction régulière, que nous pouvons voir simplement appeler la fonction FNAME.

Un autre exemple

Disons que vous aviez la signature suivante, c'est-à-dire pour quelque chose qui peut additionner deux nombres.

std::function<int(int, int)> sumFunc;

On pourrait maintenant déclarer un lambda ainsi:

sumFunc = [](int a, int b) { return a + b; };

Je ne sais pas si vous utilisez MSVC, mais voici quand même un lien vers la syntaxe d'expression lamda:

http://msdn.Microsoft.com/en-us/library/dd293603.aspx

26
Moo-Juice