Si vous pensez à une coutume, déplacer activée classe chaîne, la bonne façon d'exploiter toutes les combinaisons de catégories de valeur d'argument est:
S operator+(S const& lhs, S const& rhs);
S operator+(S && lhs, S const& rhs);
S operator+(S const& lhs, S && rhs);
S operator+(S && lhs, S && rhs);
Les fonctions renvoient un prvalue au lieu d'un xvalue. Renvoyer xvalues est généralement une chose très dangereuse – std :: move et std :: forward sont les exceptions évidentes. Si vous deviez retourner une référence rvalue vous brisaient code comme:
for (char c : my_string + other_string) {
//...
}
Cette boucle se comporte (selon 6.5.4/1 N3092) comme si le code est:
auto&& range = my_string + other_string;
Cette à son tour, il en résulte une référence pendante. La durée de vie de l'objet temporaire n'est pas étendue car votre opérateur + ne renvoie pas de prvalue. Retourner les objets par valeur est parfaitement bien. Cela va créer des objets temporaires mais ces objets sont des valeurs, donc nous pouvons voler leurs ressources pour le rendre très efficace.
Deuxièmement, votre code devrait également pas compiler pour la même raison, ce ne compilera pas:
int&& foo(int&& x) { return x; }
l'intérieur du corps x de la fonction est une lvalue et vous ne pouvez pas initialiser la « valeur de retour » (dans ce cas, la référence rvalue) avec une expression lvalue. Donc, vous auriez besoin d'une distribution explicite.
Troisièmement, il vous manque une surcharge const & + const &. Dans le cas où vos deux arguments sont des lvalues, le compilateur ne trouvera pas d'opérateur utilisable + dans votre cas.
Si vous ne voulez pas tant de surcharges, vous pouvez aussi écrire:
S operator+(S value, S const& x)
{
value += x;
return value;
}
Je ne volontairement pas écrit return value+=x;
parce que cet opérateur retourne probablement une référence lvalue qui aurait conduit à copier la construction du valeur de retour. Avec les deux lignes que j'ai écrites, la valeur de retour sera déplacée à partir de la valeur .
S x = a + b + c + d;
Au moins ce cas est très efficace, car il n'y a pas de copie, même si inutile impliqué le compilateur ne peut pas escamoter les copies – grâce à une classe de chaîne activée mouvement. En fait, avec une classe comme std :: string, vous pouvez exploiter sa fonction de membre d'échange rapide et le rendre efficace en C++ 03 et à condition que vous avez un compilateur raisonnablement intelligent (comme GCC):
S operator+(S value, S const& x) // pass-by-value to exploit copy elisions
{
S result;
result.swap(value);
result += x;
return result; // NRVO applicable
}
Voir David L'article d'Abraham Want Speed? Pass by Value. Mais ces opérateurs simples ne seront pas aussi efficaces donné:
S x = a + (b + (c + d));
Ici, le côté gauche de l'opérateur est toujours une lvalue. Comme l'opérateur + prend son côté gauche en valeur, cela conduit à de nombreuses copies. Les quatre surcharges d'en haut traitent parfaitement cet exemple aussi.
Ça fait longtemps que je n'ai pas lu la vieille diatribe de Linus. S'il se plaignait de copies inutiles en ce qui concerne std :: string, cette plainte n'est plus valide en C++ 0x, mais elle était à peine valide avant. Vous pouvez concaténer efficacement de nombreuses chaînes dans 03 C de:
S result = a;
result += b;
result += c;
result += d;
Mais en C++ 0x vous pouvez également utiliser l'opérateur + et std :: move. Ce sera très efficace aussi. J'ai effectivement regardé le code source de Git et sa gestion de chaîne (strbuf.h). Ça a l'air bien pensé. Excepté la fonction détachement/attachement, vous obtenez la même chose avec une chaîne std :: avec l'avantage évident que la ressource est automatiquement gérée par la classe elle-même, contrairement à l'utilisateur qui doit se rappeler d'appeler les bonnes fonctions à les bons moments (strbuf_init, strbuf_release).
Non déclaré dans la question: si cet ensemble est suffisant, cela signifie que nous avons 3 nouvelles surcharges à ajouter par opérateur ... Et en dehors de l'utilisation de Boost.Operator, je ne vois aucun moyen de les générer automatiquement. Du haut de ma tête cela signifie 8 'operator +' pour 'std :: string' à cause du mélange' std :: string' et 'char const *' ... –
euhh c'est horrible. Et ils appellent cela une "solution".Pfft –
@litb: Je suis d'accord avec votre sentiment ... surtout quand je pense à '-',' * ','/'et à tous les autres opérateurs similaires. Les classes numériques auront beaucoup plus de raisons d'hériter du 'boost :: addable' et je suppose. –