44 votes

Boost :: Tuples vs Structs pour les valeurs de retour

Je vais essayer d'obtenir ma tête autour de n-uplets (merci @litb), et la proposition commune pour leur utilisation pour les fonctions de renvoi > 1 valeur.

C'est quelque chose que j'avais normalement utiliser un struct , et je ne peux pas comprendre les avantages de tuples dans ce cas, il semble qu'une erreur sujettes à l'approche de la personne en phase terminale paresseux.

Empruntant un exemple, je ne l'utiliserais

struct divide_result {
    int quotient;
    int remainder;
};

À l'aide d'un tuple, vous auriez

typedef boost::tuple<int, int> divide_result;

Mais sans lire le code de la fonction vous êtes en appelant le (ou les commentaires, si vous êtes assez stupide pour leur faire confiance), vous n'avez aucune idée de ce qui l'int est le quotient et vice-versa. Il semble plutôt comme...

struct divide_result {
    int results[2]; // 0 is quotient, 1 is remainder, I think
};

...ce qui ne serait pas me remplir de confiance.

Alors, quels sont les avantages de tuples sur les structures qui permettent de compenser l'ambiguïté?

24voto

Johannes Schaub - litb Points 256113

les tuples

Je pense que je suis d'accord avec vous que le problème avec ce poste correspond à ce que la variable peut introduire de la confusion. Mais je pense qu'il y a deux côtés. L'un est l' appel côté et de l'autre est le destinataire de l'appel du côté de:

int remainder; 
int quotient;
tie(quotient, remainder) = div(10, 3);

Je pense que c'est limpide, ce que nous avons, mais il peut devenir source de confusion si vous devez retourner plusieurs valeurs à la fois. Une fois que l'appelant programmeur a regardé la documentation de l' div, il va savoir ce que la position est quoi, et pouvez écrire du code. En règle générale, je dirais de ne pas revenir à plus de 4 valeurs à la fois. Pour rien au-delà, préférez une struct.

les paramètres de sortie

Les paramètres de sortie peuvent être utilisés aussi, bien sûr:

int remainder; 
int quotient;
div(10, 3, &quotient, &remainder);

Maintenant, je pense que l'illustre la façon dont les tuples sont mieux que les paramètres de sortie. Nous avons mélangé la saisie d' div , et sa sortie, tout n'est pas gagner d'avantage. Pire, nous laissons le lecteur de code dans le doute sur ce que pourrait être la réelle valeur de retour de l' div être. Il sont de merveilleux exemples lorsque les paramètres de sortie sont utiles. À mon avis, vous devriez utiliser uniquement quand vous avez pas d'autre moyen, parce que la valeur de retour est déjà pris et ne peut pas être modifié soit un tuple ou structure. operator>> est un bon exemple de l'endroit où vous utilisez des paramètres de sortie, car la valeur de retour est déjà réservée pour le flux de données, de sorte que vous pouvez de la chaîne d' operator>> des appels. Si vous n'avez pas à faire avec des opérateurs, et le contexte n'est pas clair, je vous recommande d'utiliser des pointeurs, pour signaler à l'appel côté que l'objet est en fait utilisé comme un paramètre de sortie, en plus des commentaires le cas échéant.

de retour d'une struct

La troisième option consiste à utiliser une structure (struct):

div_result d = div(10, 3);

Je pense que certainement remporte le prix pour la clarté. Mais notez que vous avez toujours accès à la résultat à l'intérieur de cette structure, et le résultat n'est pas "mis à nu" sur la table, comme c'était le cas pour les paramètres de sortie et le n-uplet utilisé avec tie.

Je pense que d'un point majeur de ces journées est de faire tout aussi générique que possible. Donc, disons que vous avez une fonction qui permet d'imprimer des n-uplets. Vous pouvez le faire

cout << div(10, 3);

Et vous avez votre résultat affiché. Je pense que les tuples, de l'autre côté, gagne clairement pour leurs polyvalent de la nature. Que faire avec les div_result, vous avez besoin de surcharger l'opérateur<<, ou de besoin à la sortie de chaque membre séparément.

10voto

Alastair Points 2491

Une autre option consiste à utiliser une carte Boost Fusion (code non testé):

 struct quotient;
struct remainder;

using boost::fusion::map;
using boost::fusion::pair;

typedef map<
    pair< quotient, int >,
    pair< remainder, int >
> div_result;
 

Vous pouvez accéder aux résultats de manière relativement intuitive:

 using boost::fusion::at_key;

res = div(x, y);
int q = at_key<quotient>(res);
int r = at_key<remainder>(res);
 

Il existe également d'autres avantages, tels que la possibilité de parcourir les champs de la carte, etc. etc. Voir le doco pour plus d'informations.

5voto

Anteru Points 8581

Avec n-uplets, vous pouvez utiliser tie, qui est parfois très utile: std::tr1::tie (quotient, remainder) = do_division ();. Ce n'est pas facile avec des structures. Deuxièmement, lors de l'utilisation de code de modèle, il est parfois plus facile de s'appuyer sur des paires que d'en ajouter encore une autre définition de type pour le type struct.

Et si les types sont différents, puis une paire/n-uplet est vraiment pas pire qu'une struct. Pense, par exemple, pair<int, bool> readFromFile(), où l'int est le nombre d'octets lus et bool est de savoir si les expressions du folklore qui a été frappé. L'ajout d'un struct dans ce cas semble exagéré pour moi, surtout qu'il n'y a pas d'ambiguïté ici.

3voto

user21714 Points 3596

J'ai tendance à utiliser des n-uplets en conjonction avec des types de caractères pour atténuer au moins partiellement le problème du «tuple sans nom». Par exemple, si j'avais une structure en grille, alors:

 //row is element 0 column is element 1
typedef boost::tuple<int,int> grid_index;
 

Ensuite, j'utilise le type nommé comme:

 grid_index find(const grid& g, int value);
 

Ceci est un exemple quelque peu artificiel mais je pense que la plupart du temps, il trouve un juste milieu entre lisibilité, explicite et facilité d’utilisation.

Ou dans votre exemple:

 //quotient is element 0 remainder is element 1
typedef boost:tuple<int,int> div_result;
div_result div(int dividend,int divisor);
 

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