views:

112

answers:

3
template< class T1, class T2 >
class Pair {
    T1 first;
    T2 second;
};

I'm being asked to write a swap() method so that the first element becomes the second and the second the first. I have:

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

But this returns a new object rather than swapping, where I think it needs to be a void method that changes its own data members. Is this possible to do since T1 and T2 are potentially different class types? In other words I can't simply set temp=first, first=second, second=temp because it would try to convert them to different types. I'm not sure why you would potentially want to have a template object that changes order of its types as it seems that would cause confusion but that appears to be what I'm being asked to do.

Edit: Thank you all for answering! Pretty much as I thought, swapping in place obviously does not make any sense, the request for the swap() function was quite ambiguous.

+7  A: 

You cannot swap in-place, since T1 and T2 need not be of the same type. Pair<T1,T2> is a different type than Pair<T2,T1>. You have to return an object of a different type than the original one, so that has to be a new object.

What I'd do is this:

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

(There's no reason to make this a member of your Pair template.)

You could, however, add an overload for when T1 and T2 are of the same type:

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

But this, as Dennis mentioned in his comment, might be indeed very confusing.

Another idea is to define a converting constructor for your Pair template, so that implicitly convertible types can be swapped:

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) {}
};

Then you can swap like this:

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

But note that this also supports other, probably unwanted implicit conversions:

Pair<char,float> p3(p1.second, p1.first); // narrowing! 
sbi
Going from an in-place swap to an out-of-place swap based on an overload seems like a real potential source of confusion.
Dennis Zickefoose
@Dennis: I'm not sure what you're trying to tell me. `:-x`
sbi
You suggest providing an overload for when `T1` and `T2` are the same type. But this overload provides completely different semantics to the original form. `a = swap(b)` might or might not modify `b` depending on the type. That's not something I would expect.
Dennis Zickefoose
@Dennis: You are indeed right. I've added a comment regarding this.
sbi
+2  A: 

Swapping is possible only if T1 can be casted into T2 and vice-versa. If it's possible then you could write

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

(Note that you cannot change *this from a Pair<T1,T2> into a Pair<T2,T1> with this void function.)

KennyTM
+1  A: 

As pair <T1,T2> and pair <T2,T1> are different types you cannot use swap on it. Swap itself also doesn't do much more than using a temporary variable when a build-in swap operation is not given (e.g. at std::vector has one). Howeyer you can create a new type using references. Or you use pointers, where copying is cheap.

    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);
nob