Topic: Swapping std::pair<> of alien types
Author: Arno Eigenwillig <arno@mpi-sb.mpg.de>
Date: Mon, 18 Sep 2006 11:36:36 CST Raw View
Hi.
With reference to the recent discussion on swap()ing in
C++0x, I have a question regarding the following situation:
Let's say I write the following code (in my namespace C),
drawing on the standard library (in namespace std) and
some template T from an alien library L (in namespace L):
namespace C {
template <class X>
int f() {
typedef L::T<X> MyT;
typedef std::pair<int, MyT> MyPair;
MyPair pairs[2];
pairs[1] = MyPair(5, MyT(6));
pairs[0] = MyPair(3, MyT(4));
std::sort(pairs, pairs+2);
return pairs[0].first;
}
}
Let's say that operator< (L::T<X>, L::T<X>) exists so that operator<
of MyPair works. std::sort() will swap(pairs[0], pairs[1]);.
Now here are my questions:
1) Can I supply my own version of swap() to std::sort?
More specifically: In which namespace would I put it?
-- Namespace C is not related to the type std::pair< int, L::T<X> >,
so C::swap() would not be found.
-- I cannot specialize std::swap<>() partially,
and I must not overload it.
-- I should not intrude into namespace L of the alien library.
2) What if, prior to or ignorant of the changes for C++0x,
library L has its own a catch-all definition of swap():
namespace L { template<class ANY> void swap(ANY, ANY); }
?
Then the example above will not compile, because ADL runs
into an ambiguity between the catch-all swaps from std and L.
-- Whose fault is this? Wasn't this legal in C++98?
-- Should L refrain from defining a catch-all swap, even if this
requires writing an specialized swap() for each class in L?
-- Is there an exhaustive list of names other than swap
potentially affected by this phenomenon?
Thank you in advance for your wisdom,
Arno
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Tue, 19 Sep 2006 09:45:24 CST Raw View
Arno Eigenwillig wrote:
> Hi.
>
> With reference to the recent discussion on swap()ing in
> C++0x, I have a question regarding the following situation:
> Let's say I write the following code (in my namespace C),
> drawing on the standard library (in namespace std) and
> some template T from an alien library L (in namespace L):
>
> namespace C {
> template <class X>
> int f() {
> typedef L::T<X> MyT;
> typedef std::pair<int, MyT> MyPair;
> MyPair pairs[2];
> pairs[1] = MyPair(5, MyT(6));
> pairs[0] = MyPair(3, MyT(4));
> std::sort(pairs, pairs+2);
> return pairs[0].first;
> }
> }
>
> Let's say that operator< (L::T<X>, L::T<X>) exists so that operator<
> of MyPair works. std::sort() will swap(pairs[0], pairs[1]);.
>
> Now here are my questions:
>
> 1) Can I supply my own version of swap() to std::sort?
No. In practical terms std::sort relies on the processes of overload
resolution and argument dependent look-up to select the best matching
swap() routine to use for a given type. Moreover, the program will use
the general std::swap() function template for any type without a
specialized swap() routine.
In logical terms, what sense would it make for a program ever to have
more than one swap routine implemented for any type? Because no matter
how complicated or involved swapping two L::T<X> objects may be, a
single routine will always be able to implement the swap operation
completely and optimally. So it stands to reason that any swap()
routine passed to std::sort() would have to be better than the swap()
routine it preempts. Or to put it another way, any swap() routine good
enough to be used once, is also a routine good enough to be used every
time.
> More specifically: In which namespace would I put it?
> -- Namespace C is not related to the type std::pair< int, L::T<X> >,
> so C::swap() would not be found.
> -- I cannot specialize std::swap<>() partially,
> and I must not overload it.
If L::T is not Assignable or CopyConstructible, then a swap() routine
should be declared in the type's namespace, which is L in this case.
template <class X>
void swap<
> -- I should not intrude into namespace L of the alien library.
Why not? Either L::T should have its own swap routine or it should not.
And unless the library has provided its own, sanctioned way of sorting
these objects, then I don't see how avoiding "intrusion" is going to
help get the objects sorted.
The goal as I understand it is to sort objects - not to avoid
intrusion. After all, programmers write software to solve problems. And
Libraries exist to make solving those programming problems easier. So
programming is not the practice of drawing boundaries and protecting
turf between components - rather programming is the art of deploying
those components to work toward a common goal. (And, just as a
reassurance, I doubt any library author is ever going to sue a
programmer for declaring a swap routine for one of Library's classes
inside the Library's namespace [insert disclaimers here]).
> 2) What if, prior to or ignorant of the changes for C++0x,
> library L has its own a catch-all definition of swap():
> namespace L { template<class ANY> void swap(ANY, ANY); }
> ?
Then I would say it's time to start shopping for a better library.
> Then the example above will not compile, because ADL runs
> into an ambiguity between the catch-all swaps from std and L.
> -- Whose fault is this? Wasn't this legal in C++98?
It's the fault of the library for not providing a more reasonable swap
routine for the L::T class template. For example:
namespace L
{
template <class X>
void swap( T<X>& lhs, T<X>& rhs )
...
In other words, the Library only has to provide a more specialized
swap() routine than generic std::swap routine in order to avoid any
ambiguity (and that's not a tall order by any means).
> -- Should L refrain from defining a catch-all swap, even if this
> requires writing an specialized swap() for each class in L?
The std::sort function template is the 'catch all' swap routine; any
other swap() routine is therefore a specialization of one kind or
another. So if it is the (rather unlikely) case that each class in L
has its own, unique swap requirements, then yes, each class in L should
have its own swap() routine. On the other hand, it's hard to imagine
how a set of unrelated classes could all have the same, specialized
swap() requirements and yet not be related in some other way.
Greg
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]