95 votes

Implémentation d'opérateurs de comparaison via 'tuple' et 'tie', une bonne idée?

(Remarque: tuple et tie peut être pris de coup de pouce ou de C++11.)
Lors de l'écriture de petites structures avec seulement deux éléments, j'ai parfois tendance à choisir un std::pair, comme toutes les choses importantes est déjà fait pour ce type de données, comme operator< strict-faible-de la commande.
Les inconvénients mais assez inutile, les noms de variables. Même si j'ai moi-même créée typedef, je ne me souviens pas 2 jours plus tard, ce first et ce second exactement, d'autant plus si elles sont de même type. C'est encore pire depuis plus de deux membres, comme l'imbrication pairs assez bien suce.
L'autre option est un tuple, soit à partir de Boost ou de C++11, mais qui n'a pas vraiment l'air plus agréable et plus clair. Je reviens donc à l'écriture de leurs structures de moi-même, y compris les opérateurs de comparaison.
Depuis surtout l' operator< peut être assez pénible, j'ai pensé que de se soustraire à tout ce gâchis par simplement en s'appuyant sur les opérations définies pour tuple:

Exemple d' operator<, par exemple, pour un-faible-de la commande:

bool operator<(MyStruct const& lhs, MyStruct const& rhs){
  return std::tie(lhs.one_member, lhs.another, lhs.yet_more) <
         std::tie(rhs.one_member, rhs.another, rhs.yet_more);
}

(tie fait tuple de T& de références à partir d'arguments passés.)


Edit: La suggestion de @DeadMG privé afin d'hériter de tuple n'est pas mauvais, mais il est devenu tout à fait un certain nombre d'inconvénients:

  • Si les opérateurs sont en position libre (éventuellement amis), j'ai besoin d'hériter publiquement
  • Avec casting, mes fonctions / opérateurs (operator= précisément) peut être facilement contourné
  • Avec l' tie solution, je peux laisser certains membres s'ils n'ont pas d'importance pour la commande

Existe-il des inconvénients à cette mise en œuvre que j'ai besoin à considérer?

58voto

Mark B Points 60200

Cela facilitera certainement la tâche d’écrire un opérateur correct que de le lancer vous-même. Je ne dirais qu'une approche différente si le profilage montre que l'opération de comparaison prend beaucoup de temps dans votre application. Autrement, la facilité de maintenance devrait l'emporter sur les problèmes de performances éventuels.

5voto

user2369060 Points 43

Je suis tombé sur le même problème et ma solution utilise des modèles variadiques c ++11. Voici le code:

La partie .h:

 /***
 * Generic lexicographical less than comparator written with variadic templates
 * Usage:
 *   pass a list of arguments with the same type pair-wise, for intance
 *   lexiLessthan(3, 4, true, false, "hello", "world");
 */
bool lexiLessthan();

template<typename T, typename... Args>
bool lexiLessthan(const T &first, const T &second, Args... rest)
{
  if (first != second)
  {
    return first < second;
  }
  else
  {
    return lexiLessthan(rest...);
  }
}
 

Et le .cpp pour le cas de base sans arguments:

 bool lexiLessthan()
{
  return false;
}
 

Maintenant, votre exemple devient:

 return lexiLessthan(
    lhs.one_member, rhs.one_member, 
    lhs.another, rhs.another, 
    lhs.yet_more, rhs.yet_more
);
 

3voto

Puppy Points 90818

À mon avis, vous n'êtes toujours pas aborder la même question que l' std::tuple résout - à savoir, vous devez connaître à la fois le nombre et le nom de chaque variable membre, vous êtes dupliquer deux fois dans la fonction. Vous pouvez opter pour private d'héritage.

struct somestruct : private std::tuple<...> {
    T& GetSomeVariable() { ... }
    // etc
};

Cette approche est un petit peu plus de bazar pour commencer, mais vous êtes seulement en maintenant les variables et les noms en un seul endroit, plutôt que dans chaque lieu, pour chaque exploitant, vous souhaitez surcharge.

1voto

Lee Louviere Points 3352

Si vous envisagez d'utiliser plus d'une surcharge d'opérateur ou plusieurs méthodes de tuple, nous vous recommandons de faire de tuple un membre de la classe ou de dériver de tuple. Sinon, vous faites beaucoup plus de travail. Lorsque vous choisissez entre les deux, vous devez répondre à une question importante: voulez-vous que votre classe soit un tuple? Sinon, je recommanderais de contenir un tuple et de limiter l'interface à l'aide de la délégation.

Vous pouvez créer des accesseurs pour "renommer" les membres du tuple.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X