IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo

FAQ C++Consultez toutes les FAQ

Nombre d'auteurs : 34, nombre de questions : 368, dernière mise à jour : 14 novembre 2021  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de http://www.developpez.com et de l'expérience personnelle des auteurs.

Je tiens à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur ou si vous souhaitez devenir rédacteur, lisez ceci.

Sur ce, nous vous souhaitons une bonne lecture.

SommaireLa STL (15)
précédent sommaire suivant
 

Le C++ possède une bibliothèque standard (on parle aussi de SL pour Standard Library) qui est composée, entre autre, d'une bibliothèque de flux, de la bibliothèque standard du C, de la gestion des exceptions…, et de la STL (Standard Template Library : bibliothèque de modèles standard). En fait, STL est une appellation historique communément acceptée et comprise. Dans la norme on ne parle que de SL.
Comme son nom l'indique cette bibliothèque utilise fortement les templates C++ et le concept de généricité. Elle définit ainsi de nombreux modèles de classes et de fonctions génériques parmi lesquelles les conteneurs (tableau, liste, pile, ensemble…) et les algorithmes (copie, tri, recherche…) les plus courants. Une particularité importante est son approche orientée itérateurs, ce qui permet par exemple d'utiliser ses algorithmes sur d'autres conteneurs que ceux qu'elle fournit.
L'un des avantages de la STL par rapport aux autres bibliothèques remplissant (plus ou moins) le même rôle est qu'elle est standard, et donc théoriquement portable (cependant les limites de certains compilateurs compliquent la chose). Un autre avantage important est son polymorphisme paramétrique qui assure un typage fort sans exigence syntaxique à l'utilisation, c'est-à-dire par exemple que l'on peut très simplement créer un tableau de ce que l'on veut sans devoir downcaster depuis un horrible type commun tel que void *.
Utiliser la STL permet donc d'augmenter de manière significative sa productivité en C++ en écrivant du code fiable, performant et portable.

Mis à jour le 19 octobre 2004 Aurelien.Regat-Barrel LFE Luc Hermitte

Toute classe surchargeant l'opérateur d'appel de fonction operator() est qualifiée de classe foncteur (functor class). Les objets instanciés d'une telle classe sont appelés objets fonctionnels (function objects) ou foncteurs (functors). La STL utilise beaucoup ce concept pour personnaliser le comportement de ses classes/fonctions.
Notez qu'on peut tout à fait utiliser des pointeurs sur fonction au lieu de foncteurs (il suffit de pouvoir appliquer l'opérateur () à l'objet passé en paramètre), mais on préfèrera les foncteurs car ils offrent plus de performances et de flexibilité. En effet operator() peut être entièrement inliné, et on peut passer des paramètres au foncteur via son constructeur pour plus de souplesse.
Voici un exemple typique de foncteurs tiré de la question [Exemple] Comment trier une séquence selon un critère personnalisé ?

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct A  
{  
    int Number;  
    std::string String;  
};  
  
// Définition du foncteur servant à trier nos objets selon le nombre  
struct SortByNumber  
{  
    bool operator ()( const A & a1, const A & a2 ) const  
    {  
        return a1.Number < a2.Number;  
    }  
};  
  
// Définition du foncteur servant à trier nos objets selon la chaîne  
struct SortByString  
{  
    bool operator ()( const A & a1, const A & a2 ) const  
    {  
        return a1.String < a2.String;  
    }  
};
Les foncteurs sont en particulier utilisés dans le cadre des prédicats (lire Qu'est-ce qu'un prédicat ?).

Mis à jour le 18 avril 2005 Laurent Gomila

Les prédicats (predicate) sont un type particulier de foncteurs qui renvoient un booléen ou quelque chose de convertible en booléen ce qui les rend utilisables dans des expressions logiques. Il existe un certain nombre de prédicats prédéfinis dans la STL, en particulier en ce qui concerne les opérateurs logiques et arithmétiques élémentaires :

Code c++ : Sélectionner tout
1
2
3
4
5
int a = 2;  
if ( std::greater<int>()( a, 1 ) )  
{  
    // ce test est vrai car a > 1  
}
L'intérêt des prédicats est qu'ils peuvent être utilisés comme critère d'évaluation dans bon nombre d'algorithmes et conteneurs de la STL. Par exemple le conteneur std::set utilise par défaut le prédicat std::less afin d'organiser ses éléments de manière croissante. Il est facile de changer ce critère pour créer un std::set organisé de manière décroissante en spécifiant std::greater.

Code c++ : Sélectionner tout
std::set< std::greater<int> > entiersTriesParOrdreDecroissant;
Mais les prédicats révèlent toute leur puissance lorsqu'ils sont utilisés conjointement avec les foncteurs réducteurs std::bind1st et std::bind2nd. Pour plus d'informations lire À quoi servent les fonctions bind1st et bind2nd ?.

Mis à jour le 18 avril 2005 Aurelien.Regat-Barrel

std::bind1st et std::bind2nd sont un type particulier de foncteurs appelés foncteurs réducteurs. Ils permettent de facilement créer un prédicat unaire (c.a.d acceptant un seul paramètre) à partir d'un prédicat binaire (en acceptant deux paramètres). Ceci est fait en figeant la valeur d'un des deux paramètres du prédicat binaire (c.a.d. à le remplacer par une valeur fixe).
Soit l'exemple suivant où le prédicat plus_grand_que_10 est créé afin de compter grâce à std::count_if le nombre de valeurs supérieures à 10 dans un conteneur :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>  
#include <vector>  
#include <algorithm>  
  
// prédicat personnalisé permettant de tester si un  
// entier est strictement supérieur à 10  
struct plus_grand_que_10  
{  
    bool operator ()( int N ) const  
    {  
        return N > 10;  
    }  
};  
  
int main()  
{  
    std::vector<int> v;  
    v.push_back( 0 );  
    v.push_back( 5 );  
    v.push_back( 10 );  
    v.push_back( 15 );  
    v.push_back( 20 );  
  
    // compter le nombre de valeurs > 10  
    int n = std::count_if(  
        v.begin(),  
        v.end(),  
        plus_grand_que_10() ); // utilisation de notre prédicat  
  
    std::cout << n << '\n'; // affiche 2  
}
plus_grand_que_10 est un prédicat unaire obtenu en figeant le second argument de l'opérateur de comparaison supérieur à la valeur 10. On aurait pu aussi obtenir le même résultat en figeant le premier paramètre de l'opérateur inférieur cette fois-ci :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
struct plus_grand_que_10  
{  
    bool operator ()( int N ) const  
    {  
        return 10 < N;  
    }  
};
bind1st et bind2nd permettent de simplifier cette tâche fastidieuse de définition d'un prédicat binaire.
bind1st permet de figer le premier argument d'un prédicat binaire.
bind2nd permet de figer le second argument d'un prédicat binaire.
Ils s'utilisent de cette manière :

Code c++ : Sélectionner tout
<bind>( <foncteur>, <valeur du paramètre à figer> );
L'exemple précédent peut alors être simplifié ainsi:

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>  
#include <vector>  
#include <algorithm>  
#include <functional>  
  
int main()  
{  
    std::vector<int> v;  
    v.push_back( 0 );  
    v.push_back( 5 );  
    v.push_back( 10 );  
    v.push_back( 15 );  
    v.push_back( 20 );  
  
    // compter le nombre de valeurs > 10  
  
    // méthode 1 : utilisation de bind2nd pour  
    // la création d'un prédicat x > 10  
    int n = std::count_if(  
        v.begin(),  
        v.end(),  
        std::bind2nd( std::greater<int>(), 10 ) );  
  
    std::cout << n << '\n'; // affiche 2  
  
    // méthode 2 : utilisation de bind1st pour  
    // la création d'un prédicat 10 < x  
    n = std::count_if(  
        v.begin(),  
        v.end(),  
        std::bind1st( std::less<int>(), 10 ) );       
  
    std::cout << n << '\n'; // affiche 2  
}

Mis à jour le 18 avril 2005 Aurelien.Regat-Barrel

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.