Question

J'utilise des modèles C ++ pour passer dans les foncteurs de stratégie afin de changer le comportement de ma fonction. Ça fonctionne bien. Le foncteur que je passe est une classe sans état, sans stockage, qui surcharge l'opérateur () de la même manière que le foncteur.

template <typename Operation> int foo(int a) 
{
int b=Operation()(a);
/* use b here, etc */
}

Je le fais souvent, et cela fonctionne bien, et souvent je crée des modèles avec 6 ou 7 foncteurs basés sur des modèles fournis!

Cependant, je m'inquiète à la fois de l'élégance du code et de l'efficacité. Le foncteur étant sans état, je suppose donc que le constructeur Operation () est libre et que l'évaluation du foncteur est aussi efficace qu'une fonction intégrée, mais comme tous les programmeurs C ++, j'ai toujours des doutes persistants.

Ma deuxième question est de savoir si je pourrais utiliser une approche alternative de foncteur. Une autre qui ne remplace pas l'opérateur (), mais fait tout dans le constructeur comme un effet secondaire! Quelque chose comme:

struct Operation {
  Operation(int a, int &b) { b=a*a; }
};
template <typename Operation> int foo(int a) 
 {
   int b;
   Operation(a,b);
    /* use b here, etc */
 }

Je n'ai jamais vu personne utiliser un constructeur en tant que "travail". d'un foncteur, mais il semble que cela devrait fonctionner. Y a-t-il un avantage? Aucun inconvénient? J'aime bien la suppression de l'étrange parenthèse doublée "Opérateur () (a)". , mais c'est probablement juste esthétique.

Était-ce utile?

La solution

  

Des inconvénients?

  • Les acheteurs ne renvoient aucune valeur utile - ils ne peuvent pas être utilisés dans les appels chaînés (par exemple, foo (bar ()).
  • Ils peuvent lancer.
  • Point de vue de la conception - les ctors sont des fonctions de création d’objets, pas vraiment des chevaux de travail.

Autres conseils

  1. Les compilateurs insèrent en réalité le constructeur vide de Operation (au moins gcc le fait dans des situations similaires, sauf si vous avez désactivé l'optimisation)
  2. L’inconvénient de tout faire dans le constructeur est que vous ne pouvez pas créer un foncteur avec un état interne de cette façon - par exemple. foncteur pour compter le nombre d'éléments satisfaisant un prédicat. En outre, utiliser une méthode d’un objet réel en tant que foncteur vous permet de stocker son instance pour une exécution ultérieure, ce que vous ne pouvez pas faire avec votre approche constructeur.

De performance pov le code démontré avec obtenir complètement optimisé avec VC et GCC. Cependant, une meilleure stratégie consiste souvent à prendre le foncteur en tant que paramètre afin d’obtenir beaucoup plus de flexibilité et des performances identiques.

Je vous conseillerais de définir un foncteur fonctionnant avec les conteneurs STL, c’est-à-dire qu’ils devraient implémenter operator (). (Suivre l’API du langage que vous utilisez est toujours une bonne idée.)

Cela permet à vos algorithmes d’être très génériques (fonctions de transfert, fonctions, stl-bind, boost :: fonction, boost :: bind, boost :: lambda, ...) ce que l’on veut habituellement.

De cette façon, vous n'avez pas besoin de spécifier le type de foncteur en tant que paramètre de modèle, construisez simplement une instance et transmettez-la:

my_algorithm(foo, bar, MyOperation())

Il ne semble pas utile d’implémenter le constructeur dans une autre classe.
Vous ne faites que briser l’encapsulation et préparer votre classe aux abus.

Le constructeur est supposé initialiser l'objet dans un bon état tel que défini par la classe. Vous autorisez un autre objet à initialiser votre classe. Quelles garanties avez-vous que cette classe de modèle sait comment initialiser votre classe correctement? Un utilisateur de votre classe peut fournir n’importe quel objet qui pourrait perturber l’état interne de votre objet de façons non prévues.

La classe doit être autonome et s’initialiser dans un bon état. Ce que vous semblez faire, c'est jouer avec des modèles pour voir ce qu'ils peuvent faire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top