2010-05-10 7 views
3
template< class T1, class T2 > 
class Pair { 
    T1 first; 
    T2 second; 
}; 

On me demande d'écrire une méthode swap() pour que le premier élément devienne le second et le second le premier. J'ai:C++: échange d'éléments de classe de modèles de différents types?

Pair<T2,T1> swap() { 
    return Pair<T2,T1>(second, first); 
} 

Mais retourne un nouvel objet plutôt que la permutation, où je pense qu'il a besoin d'être une méthode vide qui change ses membres de données. Est-ce possible parce que T1 et T2 sont des types de classes potentiellement différents? En d'autres termes, je ne peux pas simplement définir temp = first, first = second, second = temp car il essayerait de les convertir en différents types. Je ne suis pas sûr pourquoi vous voudriez potentiellement avoir un objet de modèle qui change l'ordre de ses types car il semblerait que cela causerait la confusion mais cela semble être ce que je suis invité à faire.

Éditer: Merci à tous pour votre réponse! À peu près comme je le pensais, l'échange sur place n'a évidemment aucun sens, la demande pour la fonction swap() était assez ambiguë.

+1

Je choisirais un nom différent de 'swap'. Les personnes habituées à utiliser la bibliothèque standard penseront que «swap» est destiné à échanger le contenu de deux objets du même type. Que diriez-vous de 'flip'? –

+0

@Emile: Je ne vois pas cela comme un gros problème. C'est un 'swap()' qui prend __ un argument__ composé de __deux parties .__ Qu'est-ce que ça pourrait faire, mais les échanger? Ce qui est inhabituel, cependant, c'est que ça ne peut pas être (enfin, je ne vois pas comment, de toute façon) un échange en place. Cela diffère en effet du 'swap()' que nous avons appris à connaître. – sbi

Répondre

7

Vous ne pouvez pas échanger en place, depuis T1 et T2 doivent pas être du même type. Pair<T1,T2> est un type différent de Pair<T2,T1>. Vous devez renvoyer un objet d'un type différent de celui d'origine, il doit donc s'agir d'un nouvel objet.

Ce que je ferais est la suivante:

template< class T1, class T2 > 
Pair<T2,T1> swap(const Pair<T1,T2>& pair) { 
    return Pair<T2,T1>(pair.second, pair.first); 
} 

(Il n'y a aucune raison de faire un membre de votre modèle Pair.) Cependant,

Vous pouvez ajouter un surcharge pour lorsque T1 et T2 sont du même type:

template< class T > 
Pair<T,T>& swap(Pair<T,T>& pair) { 
    using std::swap; 
    swap(pair.first, pair.second); 
    return pair; 
} 

Mais cela, comme Dennis l'a mentionné dans son commentaire, pourrait en effet être très déroutant.

Une autre idée est de définir un constructeur conversion pour votre modèle Pair, de sorte que les types implicitement convertibles peuvent être permutés:

template< class T1, class T2 > 
class Pair { 
    T1 first; 
    T2 second; 
    template< class A1, class A2 > 
    Pair(const A1& a1, const A2& a2) : first(a1), second (a2) {} 
}; 

Ensuite, vous pouvez échanger comme ceci:

Pair<int,double> p1(42,47.11); 
Pair<double,int> p2(p1.second,p1.first); 

Notez toutefois que cela prend également en charge d'autres conversions implicites, probablement indésirables:

Pair<char,float> p3(p1.second, p1.first); // narrowing! 
+2

Passer d'un échange sur place à un échange sur place basé sur une surcharge semble être une source potentielle de confusion. –

+0

@Dennis: Je ne suis pas sûr de ce que vous essayez de me dire. ': -x' – sbi

+0

Vous suggérez de fournir une surcharge pour quand' T1' et 'T2' sont du même type. Mais cette surcharge fournit une sémantique complètement différente de la forme originale. 'a = swap (b)' pourrait ou non modifier 'b' selon le type. Ce n'est pas quelque chose que je m'attendrais. –

2

L'échange n'est possible que si T1 peut être converti en T2 et vice versa. S'il est possible, alors vous pouvez écrire

T2 temp (first); 
first = T1(second); 
second = temp; 

(Notez que vous ne pouvez pas changer *this d'un Pair<T1,T2> dans un Pair<T2,T1> avec cette fonction void.)

1

Comme pair <T1,T2> et pair <T2,T1> sont différents types que vous ne pouvez pas utiliser échange sur elle .Swap lui-même ne fait pas beaucoup plus que d'utiliser une variable temporaire quand une opération d'échange de build-in n'est pas donnée (par exemple, au std::vector en a un). Howeyer vous pouvez créer un nouveau type en utilisant des références. Ou vous utilisez des pointeurs, où la copie est bon marché.

std::pair<int, float> a = std::pair <int, float> (3,3.5); 
    std::pair<const float &, const int&> b = std::pair<const float &, const int&> (a.first, a.second);