27 votes

Cette utilisation de l'opérateur "," est-elle considérée comme une mauvaise forme?

J'ai fait une liste de classe comme un moyen de remplacer les variadic fonctions dans mon programme utilisé pour l'initialisation des objets qui ont besoin de contenir l'évolution de la liste d'éléments. La liste de classe a de l'utilisation de la syntaxe que j'aime vraiment. Cependant, je n'ai pas vu utilisé avant, donc je me demandais si je ne devrais pas utiliser tout simplement parce que de ce fait? Une base de mise en œuvre de la liste de classe ressemble à ceci...

#include <list>
#include <iostream>
template<typename T>
struct list
{
    std::list<T> items;
    list(const list&ref):items(ref.items){}
    list(){}
    list(T var){items.push_back(var);}
    list& operator,(list add_){
        items.insert(items.end(),add_.items.begin(), add_.items.end());
        return *this;
    }
    list& operator=(list add_){
        items.clear();
        items.insert(items.end(),add_.items.begin(), add_.items.end());
        return *this;
    }
    list& operator+=(list add_){
        items.insert(items.end(),add_.items.begin(), add_.items.end());
        return *this;
    }
};

Cela me permet d'avoir utiliser ce code comme si...

struct music{
//...
};
struct music_playlist{
    list<music> queue;
//...
};
int main (int argc, const char * argv[])
{
    music_playlist playlist;
    music song1;
    music song2;
    music song3;
    music song4;
    playlist.queue = song1,song2; // The queue now contains song1 and song2
    playlist.queue+= song1,song3,song4; //The queue now contains two song1s and song2-4
    playlist.queue = song2; //the queue now only contains song2
    return 0;
}

Je pense vraiment que la syntaxe est beaucoup plus agréable qu'elle ne l'aurait été si j'avais tout exposé régulièrement un conteneur stl, et même plus agréable (et typesafe) que variadic fonctions. Cependant, depuis que je n'ai pas vu cette syntaxe utilisée, je suis curieux de savoir si je doit l'éviter, car au-dessus de tout le code doit être facilement compréhensible par d'autres programmeurs?

EDIT:

En commun avec cette question, j'ai posté cette question plus ciblée sur des solutions au problème réel.

40voto

rgngl Points 2278

Pourquoi ne pas surcharger l'opérateur << comme le fait QList? Ensuite, utilisez-le comme:

 playlist.queue << song1 << song2; // The queue now contains song1 and song2
playlist.queue << song1 << song3 << song4; //The queue now contains two song1s and song2-4
 

20voto

Tom Points 3398

Je suis d'accord que votre syntaxe semble bien que vous avez écrit.
Ma principale difficulté avec le code, c'est que j'attendrais la suite pour être le même

playlist.queue = song1,song2;
playlist.queue = (song1,song2);  //more of c-style, as @Iuser notes.

alors qu'en fait ils sont complètement différents.

C'est dangereux parce qu'il est trop facile d'introduire l'utilisation de bugs dans le code. Si quelqu'un aime à utiliser des parenthèses pour ajouter un accent supplémentaire pour les groupements (pas rare), puis la virgule pourrait devenir une vraie douleur. Par exemple,

//lets combine differnt playlists
new_playlist.queue =    song1        //the first playlist
                      ,(song3,song4) //the second playlist //opps, I didn't add song 3!
                      , song5;        //the third 

ou

new_playlist.queue = (old_playlist.queue, song6); //opps, I edited my old playlist too!

Incidemment, avez-vous rencontré des boost.attribuer: http://www.boost.org/doc/libs/1_47_0/libs/assign/doc/index.html

11voto

luser droog Points 9030

La priorité a-t-elle changé récemment?

 playlist.queue = song1,song2;
 

Cela devrait être analysé comme suit:

 (playlist.queue = song1) , song2;
 

Vos ',' et '+ =' sont les mêmes! Ce serait une meilleure correspondance sémantique si votre opérateur de virgule devait créer une liste temporaire, insérer les éléments gauche et droit et renvoyer le temporaire. Ensuite, vous pourriez l'écrire comme ceci;

 playlist.queue = (song1,song2);
 

avec des parens explicites. Cela donnerait aux programmeurs C une chance de se battre pour pouvoir lire le code.

7voto

UncleBens Points 24580

Un petit problème est que si le compilateur ne peut pas choisir votre virgule d'opérateur surchargée, il peut se rabattre sur l'utilisation de l'opérateur intégré.

En revanche, avec Boost.Assign, le mélange des types produit une erreur de compilation.

 #include <boost/assign.hpp>

int main()
{
    int one = 1;
    const char* two = "2";
    list<int> li;
    li = one, two;

    using namespace boost::assign;
    std::list<int> li2;
    li2 += one, two;
}
 

5voto

Nicol Bolas Points 133791

C'est probablement quelque chose qui leur appartient plus sur les Programmeurs, mais voici mes deux cents.

Si vous parlez de code qui a une assez étroite contexte, où les utilisateurs à utiliser, en quelques endroits, et c'est tout, ensuite la surcharge de l' , opérateur est probablement OK. Si vous êtes à la construction d'un domaine spécifique de la langue qui est utilisée dans un domaine particulier et nulle part ailleurs, c'est probablement très bien.

Le problème vient quand vous êtes en surcharge pour quelque chose que vous vous attendez à ce que l'utilisateur à utiliser avec une certaine fréquence.

La surcharge , signifie que le lecteur doit complètement réinterpréter la façon de lire votre code. Ils ne peuvent pas regarder juste une expression et instantanément savoir ce qu'il fait. Vous êtes de jouer avec certains de la plupart des hypothèses de base que les programmeurs en C++ de faire quand il s'agit de la numérisation de code.

Le faire à vos propres risques et périls.

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