Pourquoi personne ne semble utiliser les tuples en C ++, que ce soit la bibliothèque Boost Tuple ou la bibliothèque standard pour TR1? J'ai lu beaucoup de code C ++ et je vois très rarement l'utilisation de tuples, mais je vois souvent beaucoup d'endroits où les tuples résoudraient de nombreux problèmes (renvoyant généralement plusieurs valeurs à partir de fonctions).
Les tuples vous permettent de faire toutes sortes de choses intéressantes comme celle-ci:
tie(a,b) = make_tuple(b,a); //swap a and b
C'est certainement mieux que ça:
temp=a;
a=b;
b=temp;
Bien sûr, vous pouvez toujours faire ceci:
swap(a,b);
Mais que faire si vous souhaitez faire pivoter trois valeurs? Vous pouvez le faire avec des tuples:
tie(a,b,c) = make_tuple(b,c,a);
Les tuples facilitent également le renvoi de plusieurs variables à partir d'une fonction, ce qui est probablement un cas beaucoup plus courant que l'échange de valeurs. Utiliser des références pour renvoyer des valeurs n'est certainement pas très élégant.
Y a-t-il de gros inconvénients aux tuples auxquels je ne pense pas? Sinon, pourquoi sont-ils rarement utilisés? Sont-ils plus lents? Ou est-ce simplement que les gens n'y sont pas habitués? Est-ce une bonne idée d'utiliser des tuples?
a = a ^ b; b = a ^ b; a = a ^ b;
Réponses:
Parce que ce n'est pas encore standard. Tout ce qui n'est pas standard a un obstacle beaucoup plus élevé. Les morceaux de Boost sont devenus populaires parce que les programmeurs les réclamaient. (hash_map me vient à l'esprit). Mais bien que le tuple soit pratique, ce n'est pas une victoire si écrasante et claire que les gens s'en soucient.
la source
Une réponse cynique est que de nombreuses personnes programment en C ++, mais ne comprennent pas et / ou n'utilisent pas les fonctionnalités de niveau supérieur. Parfois, c'est parce qu'ils ne sont pas autorisés, mais beaucoup n'essaient tout simplement pas (ou même ne comprennent pas).
À titre d'exemple sans boost: combien de personnes utilisent les fonctionnalités présentes dans
<algorithm>
?En d'autres termes, de nombreux programmeurs C ++ sont simplement des programmeurs C utilisant des compilateurs C ++, et peut
std::vector
- être etstd::list
. C'est l'une des raisons pour lesquelles l'utilisation deboost::tuple
n'est pas plus courante.la source
La syntaxe du tuple C ++ peut être un peu plus détaillée que la plupart des gens ne le souhaiteraient.
Considérer:
Donc, si vous voulez faire un usage intensif des tuples, soit vous obtenez des typedefs de tuple partout, soit vous obtenez des noms de type extrêmement longs partout. J'aime les tuples. Je les utilise quand c'est nécessaire. Mais il est généralement limité à quelques situations, comme un index à N éléments ou lors de l'utilisation de multi-cartes pour lier les paires d'itérateurs de plage. Et c'est généralement dans une portée très limitée.
Tout cela a l'air très laid et hacky par rapport à quelque chose comme Haskell ou Python. Lorsque C ++ 0x arrive ici et que nous obtenons les tuples de mot-clé 'auto', les tuples commenceront à paraître beaucoup plus attrayants.
L'utilité des tuples est inversement proportionnelle au nombre de frappes nécessaires pour les déclarer, les emballer et les décompresser.
la source
Pour moi, c'est une habitude, haut la main: les tuples ne résolvent pas de nouveaux problèmes pour moi, juste quelques-uns que je peux déjà gérer très bien. L'échange de valeurs semble toujours plus facile à l'ancienne - et, plus important encore, je ne pense pas vraiment à la façon d'échanger «mieux». C'est assez bon tel quel.
Personnellement, je ne pense pas que les tuples soient une excellente solution pour renvoyer plusieurs valeurs - cela ressemble à un travail pour
struct
s.la source
Mais que faire si vous souhaitez faire pivoter trois valeurs?
OK, donc avec 4 valeurs etc, le n-uplet devient finalement moins de code que n-1 swaps. Et avec l'échange par défaut, cela fait 6 affectations au lieu des 4 que vous auriez si vous implémentiez vous-même un modèle à trois cycles, même si j'espère que le compilateur résoudra cela pour les types simples.
Vous pouvez proposer des scénarios où les swaps sont peu maniables ou inappropriés, par exemple:
est un peu difficile à décompresser.
Le point est, cependant, qu'il existe des moyens connus de traiter les situations les plus courantes pour lesquelles les tuples sont bons, et donc pas une grande urgence de prendre des tuples. Si rien d'autre, je ne suis pas convaincu que:
ne fait pas 6 copies, ce qui le rend totalement inadapté à certains types (les collections étant les plus évidentes). N'hésitez pas à me persuader que les tuples sont une bonne idée pour les types "grands", en disant que ce n'est pas le cas :-)
Pour renvoyer plusieurs valeurs, les tuples sont parfaits si les valeurs sont de types incompatibles, mais certaines personnes ne les aiment pas s'il est possible pour l'appelant de les obtenir dans le mauvais ordre. Certaines personnes n'aiment pas du tout les valeurs de retour multiples et ne veulent pas encourager leur utilisation en les rendant plus faciles. Certaines personnes préfèrent simplement les structures nommées pour les paramètres d'entrée et de sortie, et ne pourraient probablement pas être persuadées avec une batte de baseball d'utiliser des tuples. Pas de prise en compte du goût.
la source
Comme beaucoup de gens l'ont souligné, les tuples ne sont tout simplement pas aussi utiles que les autres fonctionnalités.
Les gadgets d'échange et de rotation ne sont que des gadgets. Ils sont totalement déroutants pour ceux qui ne les ont jamais vus auparavant, et comme c'est à peu près tout le monde, ces gadgets ne sont que de mauvaises pratiques en génie logiciel.
Renvoyer plusieurs valeurs à l'aide de tuples est beaucoup moins auto-documenté que les alternatives - renvoyer des types nommés ou utiliser des références nommées. Sans cette auto-documentation, il est facile de confondre l'ordre des valeurs renvoyées, si elles sont mutuellement convertibles, et ne pas être plus sage.
la source
Tout le monde ne peut pas utiliser boost, et TR1 n'est pas encore largement disponible.
la source
Lors de l'utilisation de C ++ sur des systèmes embarqués, l'extraction des bibliothèques Boost devient complexe. Ils se couplent les uns aux autres, donc la taille de la bibliothèque augmente. Vous retournez des structures de données ou utilisez le passage de paramètres au lieu de tuples. Lors du retour de tuples en Python, la structure de données est dans l'ordre et le type des valeurs renvoyées, ce n'est tout simplement pas explicite.
la source
Vous les voyez rarement car un code bien conçu n'en a généralement pas besoin - il n'y a pas beaucoup de cas dans la nature où l'utilisation d'une structure anonyme est supérieure à l'utilisation d'une structure nommée. Puisque tout ce qu'un tuple représente vraiment est une structure anonyme, la plupart des codeurs dans la plupart des situations vont simplement avec la vraie chose.
Supposons que nous ayons une fonction "f" où un retour de tuple pourrait avoir un sens. En règle générale, ces fonctions sont généralement suffisamment compliquées pour qu’elles puissent échouer.
Si "f" PEUT échouer, vous avez besoin d'un retour d'état - après tout, vous ne voulez pas que les appelants doivent inspecter chaque paramètre pour détecter un échec. "f" s'inscrit probablement dans le motif:
Ce n'est pas joli, mais regardez à quel point l'alternative est laide. Notez que j'ai toujours besoin d'une valeur de statut, mais le code n'est ni plus lisible ni plus court. C'est probablement plus lent aussi, puisque j'encourt le coût d'une copie avec le tuple.
Un autre inconvénient important est caché ici - avec "ReturnInts", je peux ajouter le retour de "f" en modifiant "ReturnInts" SANS ALTÉRER L'INTERFACE de "f". La solution tuple n'offre pas cette fonctionnalité critique, ce qui en fait la réponse inférieure pour tout code de bibliothèque.
la source
using std::tuple;
et en utilisant simplementtuple
le code.tuple
rend le code moins lisible, pas plus. La plupart des codes de nos jours contiennent un très grand nombre de symboles - voirstd::tuple
clairement ce que c'est.Les tuples peuvent certainement être utiles, mais comme mentionné, il y a un peu de surcharge et un obstacle ou deux que vous devez franchir avant de pouvoir même les utiliser vraiment.
Si votre programme trouve systématiquement des endroits où vous devez renvoyer plusieurs valeurs ou échanger plusieurs valeurs, cela peut valoir la peine d'emprunter la route du tuple, mais sinon, il est parfois plus facile de faire les choses de manière classique.
De manière générale, Boost n'est pas déjà installé sur tout le monde, et je n'aurais certainement pas à me soucier de le télécharger et de configurer mes répertoires d'inclusion pour qu'il fonctionne uniquement pour ses fonctionnalités de tuple. Je pense que vous constaterez que les personnes qui utilisent déjà Boost sont plus susceptibles de trouver des utilisations de tuple dans leurs programmes que les utilisateurs non-Boost, et les migrants d'autres langues (Python vient à l'esprit) sont plus susceptibles d'être simplement contrariés par le manque de tuples en C ++ que d'explorer des méthodes d'ajout de support de tuple.
la source
En tant que magasin de données
std::tuple
a les pires caractéristiques de astruct
et d'un tableau; tout accès est basé sur la nième position mais on ne peut pas parcourirtuple
unefor
boucle en utilisant une boucle.Donc, si les éléments du
tuple
sont conceptuellement un tableau, j'utiliserai un tableau et si les éléments ne sont pas conceptuellement un tableau, une structure (qui a des éléments nommés) est plus facile à maintenir. (a.lastname
est plus explicatif questd::get<1>(a)
).Cela laisse la transformation mentionnée par l'OP comme le seul cas d'utilisation viable pour les tuples.
la source
J'ai le sentiment que beaucoup utilisent Boost.Any et Boost.Variant (avec un peu d'ingénierie) au lieu de Boost.Tuple.
la source