Prédicats et foncteurs d’opérateurs logiques
Les foncteurs qui peuvent être utilisés dans une expression logique constituent une classe particulière : les prédicats. Un prédicat est un foncteur dont l’opérateur fonctionnel renvoie un booléen. Les prédicats ont donc un sens logique, et caractérisent une propriété qui ne peut être que vraie ou fausse.
La bibliothèque standard fournit des prédicats prédéfinis qui effectuent les opérations logiques des opérateurs logiques de base du langage. Ces prédicats sont également déclarés dans l’en-tête functional :
template <class T> struct logical_and : binary_function<T, T, bool> { bool operator()(const T &operande1, const T &operande2) const;
};
template <class T> struct logical_or : binary_function<T, T, bool> { bool operator()(const T &operande1, const T &operande2) const; };
Ces foncteurs fonctionnent exactement comme les foncteurs vus dans la section précédente.
La bibliothèque standard définit aussi deux foncteurs particuliers, qui permettent d’effectuer la négation d’un autre prédicat. Ces deux foncteurs travaillent respectivement sur les prédicats unaires et sur les prédicats binaires :
template <class Predicate> class unary_negate : public unary_function<typename Predicate::argument_type, bool> { public: explicit unary_negate(const Predicate &predicat); bool operator()(const argument_type &argument) const; };
template <class Predicate> class binary_negate : public binary_function<typename Predicate::first_argument_type, typename Predicate::second_argument_type, bool> { public: explicit binary_negate(const Predicate &predicat); bool operator()(const first_argument_type &argument1, const second_argument_type &argument2) const; };
template <class Predicate> unary_negate<Predicate> not1(const Predicate &predicat);
template <class Predicate> binary_negate<Predicate> not2(const Predicate &predicat);
Les fonctions not1 et not2 servent à faciliter la construction d’un prédicat inverse pour les prédicats unaires et binaires.
Foncteurs réducteurs
Nous avons vu que la bibliothèque standard ne travaillait qu’avec des foncteurs prenant au plus deux arguments. Certains algorithmes n’utilisant que des foncteurs unaires, ils ne sont normalement pas capables de travailler avec les foncteurs binaires. Toutefois, si un des paramètres d’un foncteur binaire est fixé à une valeur donnée, celui-ci devient unaire, puisque seul le deuxième paramètre peut varier. Il est donc possible d’utiliser des foncteurs binaires même avec des algorithmes qui n’utilisent que des foncteurs unaires, à la condition de fixer l’un des paramètres.
La bibliothèque standard définit des foncteurs spéciaux qui permettent de transformer tout foncteur binaire en foncteur unaire à partir de la valeur de l’un des paramètres. Ces foncteurs effectuent une opération dite de réduction car ils réduisent le nombre de paramètres du foncteur binaire à un. Pour
cela, ils définissent un opérateur fonctionnel à un argument, qui applique l’opérateur fonctionnel du foncteur binaire à cet argument et à une valeur fixe qu’ils mémorisent en donnée membre.
Ces foncteurs réducteurs sont déclarés, comme les autres foncteurs, dans l’en-tête fonctional :
template <class Operation> class binder1st : public unary_function<typename Operation::second_argument_type, typename Operation::result_type> { protected: Operation op; typename Operation::first_argument_type value; public: binder1st(const Operation &foncteur, const typename Operation::first_argument_type &valeur); result_type operator()(const argument_type &variable) const; };
template <class Operation> class binder2nd : public unary_function<typename Operation::first_argument_type, typename Operation::result_type> { protected: Operation op; typename Operation::second_argument_type value; public: binder2nd(const Operation &foncteur, const typename Operation::second_argument_type &valeur); result_type operator()(const argument_type &variable) const; };
template <class Operation, class T> binder1st<Operation> bind1st(const Operation &foncteur, const T &valeur);
template <class Operation, class T> binder2nd<Operation> bind2nd(const Operation &foncteur, const T &valeur);
Il existe deux jeux de réducteurs, qui permettent de réduire les foncteurs binaires en fixant respectivement leur premier ou leur deuxième paramètre. Les réducteurs qui figent le premier paramètre peuvent être construits à l’aide de la fonction template bind1st, et ceux qui figent la valeur du deuxième paramètre peuvent l’être à l’aide de la fonction bind2nd.
#include <iostream> #include <functional>
using namespace std;
// Fonction template permettant d’appliquer une valeur // à un foncteur unaire. Cette fonction ne peut pas // être utilisée avec un foncteur binaire. template <class Foncteur> typename Foncteur::result_type applique(
Foncteur f, typename Foncteur::argument_type valeur)
{
return f(valeur);
}
int main(void) { // Construit un foncteur binaire d’addition d’entiers : plus<int> plus_binaire; int i; for (i = 0; i < 10; ++i) { // Réduit le foncteur plus_binaire en fixant son // premier paramètre à 35. Le foncteur unaire obtenu // est ensuite utilisé avec la fonction applique : cout << applique(bind1st(plus_binaire, 35), i) << endl; } return 0; }