Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Namespace issue with specialized swap

565 views
Skip to first unread message

nik...@my-deja.com

unread,
Mar 12, 2000, 3:00:00 AM3/12/00
to
A specialized swap function can often be more efficient than
the general purpose version. But if I implement a swap function
for a class which is in a namespace, how can I make sure my
function gets called instead of std::swap?

Following is a program that demonstrates the problem. Namespace
"A" contains a stripped-down smart pointer class P, which has
a specialized swap function. To help Illustrate, I made P
non-assignable so that calling std::swap produces an error.

namespace A {

template<class T>
class P {
public:
P(T* in) { p = in; }
~P() { delete p; }

void swap(P& arg) {
T* temp = p;
p = arg.p;
arg.p = temp; }

friend void swap(P& p1, P& p2) {
p1.swap(p1); }

private:
T* p;
P& operator=(const P& rhs);
P(const P& rhs);
};
};

template<class T>
void MyFunc(T& lhs, T& rhs)
{
std::swap(lhs, rhs);
}

namespace std {

template<class T>
void standard_function(T& lhs, T& rhs)
{
swap(lhs, rhs);
}
}

int main()
{
using namespace std;
using namespace A;

P<int> p1 = new int(1);
P<int> p2 = new int(2);

swap(p1, p2);
MyFunc(p1, p2);
standard_function(p1, p2);

return 0;
}


Let's look at the three calls to swap in this program. First,
the call to swap in the main function resolves to A::swap, which
is what I want. That's because main "uses" both namespaces, so
A::swap and std::swap are equally visible.

Second, the MyFunc function contains no using statements so it
explicitly specifies the std namespace. Not surprisingly, this
results in a call to std::swap, which for class P results in a
compile-time error.

Finally, I included standard_function to illustrate what might
happen if I used my class with a hypothetical standard library
function. Since this function is itself in the std namespace,
its call to swap results in a call to std::swap.

None of this is terribly surprising, but it leads me to wonder:
if I take the trouble to write a specialized swap function, how
can I make sure it gets called? The only solution I can think of
is to put my swap function in the std namespace, but this seems
like a no-no. Any suggestions?


Sent via Deja.com http://www.deja.com/
Before you buy.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]


Darin Adler

unread,
Mar 13, 2000, 3:00:00 AM3/13/00
to
In article <8abr6r$478$1...@nnrp1.deja.com>, nik...@my-deja.com wrote:

> None of this is terribly surprising, but it leads me to wonder:
> if I take the trouble to write a specialized swap function, how
> can I make sure it gets called? The only solution I can think of
> is to put my swap function in the std namespace, but this seems
> like a no-no. Any suggestions?

Your swap should go in the std namespace. A *specialization* of
std::swap is allowed for non-template classes because of the following
clause in the standard (part of 17.4.3.1/1):

"A program may add template specializations for any standard library
template to namespace std. Such a specialization (complete or partial)
of a standard library template results in undefined behavior unless the
declaration depends on a user-defined name of external linkage and
unless the specialization meets the standard library requirements for
the original template."

Unfortunately, as I understand it, for a template class, putting your
swap in the standard namespace requires an overload of the std::swap
function template rather than a specialization. This overload has pretty
much the same effect as a specialization, but it's theoretically illegal
because the clause above only talks about specializations.

My approach has been to put the overload in namespace std and hope that
the standard gets revised to allow this some day. For example, I did
this in the Boost <http://www.boost.org> header smart_ptr.hpp for the
class templates shared_ptr and shared_array.

Someone should write a defect report about this issue eventually. I
haven't been able to boil down the thing to my satisfaction which is why
I haven't written one yet.

-- Darin

Siemel B. Naran

unread,
Mar 13, 2000, 3:00:00 AM3/13/00
to
On 12 Mar 2000 06:59:29 -0500, nik...@my-deja.com <nik...@my-deja.com> wrote:

>A specialized swap function can often be more efficient than
>the general purpose version. But if I implement a swap function
>for a class which is in a namespace, how can I make sure my
>function gets called instead of std::swap?

namespace std
{
void swap(P& lhs, P& rhs) { lhs.swap(rhs); }
}

--
--------------
siemel b naran
--------------

Howard Hinnant

unread,
Mar 13, 2000, 3:00:00 AM3/13/00
to
In article <8abr6r$478$1...@nnrp1.deja.com>, nik...@my-deja.com wrote:

> Finally, I included standard_function to illustrate what might
> happen if I used my class with a hypothetical standard library
> function. Since this function is itself in the std namespace,
> its call to swap results in a call to std::swap.

This doesn't answer your entire question, but I wanted to point out that
standard_function(p1, p2); will call A::swap because of Koenig lookup.

-Howard

Todd Greer

unread,
Mar 14, 2000, 3:00:00 AM3/14/00
to
nik...@my-deja.com writes:

> None of this is terribly surprising, but it leads me to wonder:
> if I take the trouble to write a specialized swap function, how
> can I make sure it gets called? The only solution I can think of
> is to put my swap function in the std namespace, but this seems
> like a no-no. Any suggestions?

Specializing std templates with user-defined types is explicitly
allowed. Thus, write:

namespace std
{
template<class T>

void swap(P<T>& a, P<T>& b) {...}
}

(I just typed this out without compiling it, so there are probably
mistakes.)

I think this should be the preferred way to write swap, for the
reasons you give.

--
Todd Greer <tgr...@acm.org>

Gabriel Dos Reis

unread,
Mar 15, 2000, 3:00:00 AM3/15/00
to
Todd Greer <tgr...@acm.org> writes:

| nik...@my-deja.com writes:
|
| > None of this is terribly surprising, but it leads me to wonder:
| > if I take the trouble to write a specialized swap function, how
| > can I make sure it gets called? The only solution I can think of
| > is to put my swap function in the std namespace, but this seems
| > like a no-no. Any suggestions?
|
| Specializing std templates with user-defined types is explicitly
| allowed. Thus, write:
|
| namespace std
| {
| template<class T>
| void swap(P<T>& a, P<T>& b) {...}
| }

No, this is wrong.

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

alan_gr...@my-deja.com

unread,
Mar 15, 2000, 3:00:00 AM3/15/00
to
In article <uog8hb...@nonsense.dy.natinst.com>,

Todd Greer <tgr...@acm.org> wrote:
>
> Specializing std templates with user-defined types is explicitly
> allowed. Thus, write:
>
> namespace std
> {
> template<class T>
> void swap(P<T>& a, P<T>& b) {...}
> }

The code you give _overloads_ the std::swap<> template function. This
is currently disallowed - although the issue has been discussed in a
number of forums.

A specialisation looks like:

namespace std
{
template<>
void swap(myspace::mytype& a, myspace::mytype& a) { ... }
}

IMHO opinion overloading of standard algorithms based on UDTs (what
you've done) should be allowed. (And is what I do.)

Informally I know what I want the standard to say, but I keep being
distracted from writing a defect report...

... should any std functions be overloadable (e.g. std::abs when I write
a big_integer<> template class).

... if so, what about "impure" functions from the C heritage (e.g.
std::strtok).

... what about interactions with the implicit conversion rules if
"big_integer" has a non-explicit constructor taking a "double".
--
Alan Griffiths (alan.gr...@experian.com, +44 115 934 4517)
Senior Systems Consultant, Experian


Sent via Deja.com http://www.deja.com/
Before you buy.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Jonathan Lundquist

unread,
Mar 16, 2000, 3:00:00 AM3/16/00
to
On 15 Mar 2000 23:13:39 -0500, alan_gr...@my-deja.com wrote:

>In article <uog8hb...@nonsense.dy.natinst.com>,
>Todd Greer <tgr...@acm.org> wrote:
>>
>> Specializing std templates with user-defined types is explicitly
>> allowed. Thus, write:
>>
>> namespace std
>> {
>> template<class T>
>> void swap(P<T>& a, P<T>& b) {...}
>> }
>
>The code you give _overloads_ the std::swap<> template function. This
>is currently disallowed - although the issue has been discussed in a
>number of forums.

It looks to me like partial specialisation? Any standard lawyers care
to comment?

>
>A specialisation looks like:
>
>namespace std
>{
> template<>
> void swap(myspace::mytype& a, myspace::mytype& a) { ... }
>}

>...

Gabriel Dos Reis

unread,
Mar 17, 2000, 3:00:00 AM3/17/00
to
Jonathan Lundquist <j...@sssonline.com> writes:

| On 15 Mar 2000 23:13:39 -0500, alan_gr...@my-deja.com wrote:
|
| >In article <uog8hb...@nonsense.dy.natinst.com>,
| >Todd Greer <tgr...@acm.org> wrote:
| >>
| >> Specializing std templates with user-defined types is explicitly
| >> allowed. Thus, write:
| >>
| >> namespace std
| >> {
| >> template<class T>
| >> void swap(P<T>& a, P<T>& b) {...}
| >> }
| >
| >The code you give _overloads_ the std::swap<> template function. This
| >is currently disallowed - although the issue has been discussed in a
| >number of forums.
|
| It looks to me like partial specialisation? Any standard lawyers care
| to comment?

I'm not a standard lawyer, but I can say for sure that there is not
such as a *partial* specializaton for template function. The above is an
overloading. Given a template function, you can:
o fully specialize it, or
o overload it.

That is all.

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Biju Thomas

unread,
Mar 17, 2000, 3:00:00 AM3/17/00
to
Jonathan Lundquist wrote:
>
> On 15 Mar 2000 23:13:39 -0500, alan_gr...@my-deja.com wrote:
>
> >In article <uog8hb...@nonsense.dy.natinst.com>,
> >Todd Greer <tgr...@acm.org> wrote:
> >>
> >> Specializing std templates with user-defined types is explicitly
> >> allowed. Thus, write:
> >>
> >> namespace std
> >> {
> >> template<class T>
> >> void swap(P<T>& a, P<T>& b) {...}
> >> }
> >
> >The code you give _overloads_ the std::swap<> template function. This
> >is currently disallowed - although the issue has been discussed in a
> >number of forums.
>
> It looks to me like partial specialisation? Any standard lawyers care
> to comment?
>

Not a lawyer, but, the above code is *not* partial specialization, but
overloading. A partial specialization syntax would have been (if it was
legal):

template < class T >
void swap<T> ( P<T>&, P<T>& ) {...}

--
Biju Thomas

Andrei Alexandrescu

unread,
Mar 17, 2000, 3:00:00 AM3/17/00
to
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
news:flln3k5...@riz.cmla.ens-cachan.fr...
> No, this is wrong.

As much as I appreciate terseness, this is not too enlighting :o).

C'mon, man - why aren't you more, well, joyful? Reminds me of our discussion
about valarray. You did give us a lot of information, but only after a lot
of persuasion efforts.

Why is that wrong?


Andrei

Darin Adler

unread,
Mar 17, 2000, 3:00:00 AM3/17/00
to
In article <Jg7ROE8lVXxxDp...@4ax.com>, Jonathan Lundquist
<j...@sssonline.com> wrote:

> On 15 Mar 2000 23:13:39 -0500, alan_gr...@my-deja.com wrote:
>
> >In article <uog8hb...@nonsense.dy.natinst.com>,
> >Todd Greer <tgr...@acm.org> wrote:
> >>
> >> Specializing std templates with user-defined types is explicitly
> >> allowed. Thus, write:
> >>
> >> namespace std
> >> {
> >> template<class T>
> >> void swap(P<T>& a, P<T>& b) {...}
> >> }
> >
> >The code you give _overloads_ the std::swap<> template function. This
> >is currently disallowed - although the issue has been discussed in a
> >number of forums.
>
> It looks to me like partial specialisation? Any standard lawyers care
> to comment?

There's no such thing as partial specialization for function templates.
It only exists for class templates. For function templates you get a
similar effect by using one function template to overload another.

Partial specialization of class template is covered in section 14.5.4 of
the standard. The next section, 14.5.5, discusses function template
overloading. There's no section discussing function temlate partial
specialization; it doesn't exist.

-- Darin

Gabriel Dos Reis

unread,
Mar 18, 2000, 3:00:00 AM3/18/00
to
"Andrei Alexandrescu" <andre...@hotmail.com> writes:

[...]

| Why is that wrong?


> Specializing std templates with user-defined types is explicitly
> allowed. Thus, write:

> namespace std
> {
> template<class T>
> void swap(P<T>& a, P<T>& b) {...}
> }

The above is not an explicit template specialization as claimed.
(But you know that. Isn't it?)

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

nik...@my-deja.com

unread,
Mar 18, 2000, 3:00:00 AM3/18/00
to
In article <8ankpq$9da$1...@nnrp1.deja.com>,

alan_gr...@my-deja.com wrote:
> In article <uog8hb...@nonsense.dy.natinst.com>,
> Todd Greer <tgr...@acm.org> wrote:
> >
> > Specializing std templates with user-defined types is explicitly
> > allowed. Thus, write:
> >
> > namespace std
> > {
> > template<class T>
> > void swap(P<T>& a, P<T>& b) {...}
> > }
>
> The code you give _overloads_ the std::swap<> template function. This
> is currently disallowed - although the issue has been discussed in a
> number of forums.
Actually, I don't think it's either a partial specialization
_or_ an overload, but is simply ambiguous. At least, that's
what my compiler thinks, and I think in this case my compiler
is right.
Perhaps the idea that this is an overload derives from the
example (excerpted below) from 14.5.5.2 [temp.func.order]:
template<class T> void h(const T&);
template<class T> void h(A<T>&);
...
h(z); // overload resolution selects h(A<T>&)
Here the comment implies that neither function is more
specialized than the other; therefore the second function
is selected based on the overloading rules. But having
looked at the overloading rules, I think the _only_ reason
this call is not ambiguous is because the first function
takes a const reference!
So if I want to write a specialized version of std::swap
for my own template class, it seems I'm out of luck. If I
don't put my swap function in the std namespace it simply
won't get called in most cases, but if I do put it in the
std namespace it will be ambiguous. No method of resolving
the ambiguity seem to work:
- Partial specialization of templates doesn't help.
- Overloading per 13.3.3 doesn't give a best match.
- Making std::swap a friend might solve the ambiguity,
but can't (I think) be done if my template class
and std::swap are in different namespaces.
This seems like something many people would want to do.
Can it really be impossible?


Sent via Deja.com http://www.deja.com/
Before you buy.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gabriel Dos Reis

unread,
Mar 18, 2000, 3:00:00 AM3/18/00
to
nik...@my-deja.com writes:

| In article <8ankpq$9da$1...@nnrp1.deja.com>,
| alan_gr...@my-deja.com wrote:
| > In article <uog8hb...@nonsense.dy.natinst.com>,
| > Todd Greer <tgr...@acm.org> wrote:
| > >
| > > Specializing std templates with user-defined types is explicitly
| > > allowed. Thus, write:
| > >
| > > namespace std
| > > {
| > > template<class T>
| > > void swap(P<T>& a, P<T>& b) {...}
| > > }
| >
| > The code you give _overloads_ the std::swap<> template function. This
| > is currently disallowed - although the issue has been discussed in a
| > number of forums.
| Actually, I don't think it's either a partial specialization
| _or_ an overload, but is simply ambiguous.

???

13/1:
When two or more different declarations are specified for a single
name in the same scope, that name is said to be overloaded. [...]

| ... At least, that's


| what my compiler thinks, and I think in this case my compiler
| is right.
| Perhaps the idea that this is an overload derives from the
| example (excerpted below) from 14.5.5.2 [temp.func.order]:
| template<class T> void h(const T&);
| template<class T> void h(A<T>&);

No, it comes from the standard definition.

| ...
| h(z); // overload resolution selects h(A<T>&)
| Here the comment implies that neither function is more
| specialized than the other; therefore the second function
| is selected based on the overloading rules. But having
| looked at the overloading rules, I think the _only_ reason
| this call is not ambiguous is because the first function
| takes a const reference!

Well, partial ordering rules and overloading resolution rules are
different concepts from the concept of "overloading".

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Andrei Alexandrescu

unread,
Mar 18, 2000, 3:00:00 AM3/18/00
to
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
news:flhfe5f...@poivre.cmla.ens-cachan.fr...
[snip]

> > namespace std
> > {
> > template<class T>
> > void swap(P<T>& a, P<T>& b) {...}
> > }
>
> The above is not an explicit template specialization as claimed.
> (But you know that. Isn't it?)

(I didn't.)
Ah, you mean only total specializations of std functions are allowed? Like:

namespace std
{
template<>
void swap(P<int>& a, P<int>& b) {...}
}

In this case, we're kinda stuck. If we develop a matrix class template,
we're not able to make swap matrices of any type efficiently.


Andrei

Andrei

Gabriel Dos Reis

unread,
Mar 19, 2000, 3:00:00 AM3/19/00
to
"Andrei Alexandrescu" <andre...@hotmail.com> writes:

| Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
| news:flhfe5f...@poivre.cmla.ens-cachan.fr...
| [snip]
| > > namespace std
| > > {
| > > template<class T>
| > > void swap(P<T>& a, P<T>& b) {...}
| > > }
| >
| > The above is not an explicit template specialization as claimed.
| > (But you know that. Isn't it?)
|
| (I didn't.)

I'm surprised ;-)

| Ah, you mean only total specializations of std functions are allowed? Like:
|
| namespace std
| {
| template<>
| void swap(P<int>& a, P<int>& b) {...}
| }

Yes. The standard says:

17.4.3.1/1
It is undefined for a C++ program to add declarations or definitions
to namespace std or namespaces with namespace std unless otherwise
specified. A program may add template specializations for any


standard library template to namespace std. Such a specialization

(complete or partial) of a standard library results in undefined
behaviour unless the declaration depends on a user-defined name of
external linkage and unless the template specialization meets the


standard library requirements for the original template.

| In this case, we're kinda stuck. If we develop a matrix class template,
| we're not able to make swap matrices of any type efficiently.

Please, could you elaborate on this a little bit?

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Andrei Alexandrescu

unread,
Mar 19, 2000, 3:00:00 AM3/19/00
to
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
news:flityj5...@poivre.cmla.ens-cachan.fr...

> | In this case, we're kinda stuck. If we develop a matrix class template,
> | we're not able to make swap matrices of any type efficiently.
>
> Please, could you elaborate on this a little bit?

I meant: I make a Matrix class template. Then I want to implement an


efficient swap for it. I then write:

namespace std
{
template <class T> inline void swap(Matrix<T>& lhs, Matrix<T>& rhs)
{
...
}
}

What you say implies that I must write:

namespace std
{
template <> inline void swap(Matrix<int>& lhs, Matrix<int>& rhs)
{
...
}
template <> inline void swap(Matrix<double>& lhs, Matrix<double>& rhs)
{
...
}
...
}

Is that correct? After all, how does one call a partial ordering of
functions? Does it count as overloading?


Andrei

Ross Smith

unread,
Mar 19, 2000, 3:00:00 AM3/19/00
to
"Gabriel Dos Reis" <dos...@cmla.ens-cachan.fr> wrote in message
news:flityj5...@poivre.cmla.ens-cachan.fr...
> "Andrei Alexandrescu" <andre...@hotmail.com> writes:
>
> | Ah, you mean only total specializations of std functions are
allowed? Like:
> |
> | namespace std
> | {
> | template<>
> | void swap(P<int>& a, P<int>& b) {...}
> | }
>
> Yes. The standard says:
>
> 17.4.3.1/1
> It is undefined for a C++ program to add declarations or definitions
> to namespace std or namespaces with namespace std unless otherwise
> specified. A program may add template specializations for any
> standard library template to namespace std. Such a specialization
> (complete or partial) of a standard library results in undefined
> behaviour unless the declaration depends on a user-defined name of
> external linkage and unless the template specialization meets the
> standard library requirements for the original template.

I don't see how this supports your claim. It seems to me to say that
partial specialisation *is* allowed if it depends on a user-defined name
(as in Andrei's earlier example).

--
Ross Smith <ros...@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"So that's 2 T-1s and a newsfeed ... would you like clues with that?"
-- Peter Da Silva

Gabriel Dos Reis

unread,
Mar 20, 2000, 3:00:00 AM3/20/00
to
"Andrei Alexandrescu" <andre...@hotmail.com> writes:

| Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
| news:flityj5...@poivre.cmla.ens-cachan.fr...

| > | In this case, we're kinda stuck. If we develop a matrix class template,
| > | we're not able to make swap matrices of any type efficiently.
| >
| > Please, could you elaborate on this a little bit?
|
| I meant: I make a Matrix class template. Then I want to implement an
| efficient swap for it. I then write:
|
| namespace std
| {
| template <class T> inline void swap(Matrix<T>& lhs, Matrix<T>& rhs)
| {
| ...
| }
| }
|
| What you say implies that I must write:
|
| namespace std
| {
| template <> inline void swap(Matrix<int>& lhs, Matrix<int>& rhs)
| {
| ...
| }
| template <> inline void swap(Matrix<double>& lhs, Matrix<double>& rhs)
| {
| ...
| }
| ...
| }
|
| Is that correct?

No. What the standard says is that if you *insist* to put
'swap(Matrix<>&, Matrix<>&)' in namespace std, then you don't have the
choice: Matrix<> must be full specialization, it can't depend on a
template parameter.

Why can't you put 'swap(Matrix<>&, Matrix<>&)' in Matrix's namespace
definition?

| ... After all, how does one call a partial ordering of


| functions? Does it count as overloading?

Partial ordering of template function is a _rule_ used to select a
template function declaration associated with a function template
specialization in case the function template is overloaded.

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gabriel Dos Reis

unread,
Mar 20, 2000, 3:00:00 AM3/20/00
to
"Ross Smith" <ros...@ihug.co.nz> writes:

| "Gabriel Dos Reis" <dos...@cmla.ens-cachan.fr> wrote in message
| news:flityj5...@poivre.cmla.ens-cachan.fr...

| > "Andrei Alexandrescu" <andre...@hotmail.com> writes:
| >
| > | Ah, you mean only total specializations of std functions are
| allowed? Like:
| > |
| > | namespace std
| > | {
| > | template<>
| > | void swap(P<int>& a, P<int>& b) {...}
| > | }
| >
| > Yes. The standard says:
| >
| > 17.4.3.1/1
| > It is undefined for a C++ program to add declarations or definitions
| > to namespace std or namespaces with namespace std unless otherwise
| > specified. A program may add template specializations for any
| > standard library template to namespace std. Such a specialization
| > (complete or partial) of a standard library results in undefined
| > behaviour unless the declaration depends on a user-defined name of
| > external linkage and unless the template specialization meets the
| > standard library requirements for the original template.
|
| I don't see how this supports your claim. It seems to me to say that
| partial specialisation *is* allowed if it depends on a user-defined name
| (as in Andrei's earlier example).

But as I said in another message

template<typename T>
void swap(P<T>&, P<T>&) { /* ... */ }

is *not* a partial specialization. It is an overloading. Thus
it can be put put in namespace std, as per the rule quoted above.

There is nothing named *template function partial specialization*.
The only thing you have with template function is
o explicit (i.e. full) specialization
o overloading.

That is all.

alan_gr...@my-deja.com

unread,
Mar 20, 2000, 3:00:00 AM3/20/00
to
In article <8b3ctg$ni3$1...@news.ihug.co.nz>,

"Ross Smith" <ros...@ihug.co.nz> wrote:
> I don't see how this supports your claim. It seems to me to say that
> partial specialisation *is* allowed if it depends on a user-defined
name
> (as in Andrei's earlier example).

Before partial specialisation is allowed it must exist:

In article <darin-CBCBF4....@fullnews.metawire.com>,


Darin Adler <da...@bentspoon.com> wrote:
> There's no such thing as partial specialization for function
templates.
> It only exists for class templates. For function templates you get a
> similar effect by using one function template to overload another.
>
> Partial specialization of class template is covered in section 14.5.4
of
> the standard. The next section, 14.5.5, discusses function template
> overloading. There's no section discussing function temlate partial
> specialization; it doesn't exist.

(I.e. Andrei's earlier example overloads the swap template.)

There are many reasons to want to provide "partial specialisations" of
the standard algorithms (such as Andrei's Matrix). But it is not
allowed by the language - the obvious alternative of overloading in
namespace std is better (only "undefined behavior") but not ideal.

An alternative is to provide swap<>(Matrix<T>&, Matrix<T>&) in the
namespace that contains Matrix - but that has problems too. (Think of
writing code that uses Matrix in a class with a swap() member function.
Too easy? Try a template class that could be passed Matrix as a
parameter.)

This last can be made to work if the writer of the client code is
sufficiently aware of the issues - but I don't think that requirement is
acceptable. Look at the current thread - the participants are all
"above average" in their knowledge and interest in standard C++. The
name lookup problem and the route around it are similarly obscure (i.e.
you only know about it after being bitten).

PS

I'm not the only one that knowingly relies on "undefined behavior" in
this area - check out the boost smart pointers (http://www.boost.org/).
AFAIK there is no ideal solution in the language as currently defined.
When I can work out what the standard should say I'll submit a defect
report. (But this isn't easy either.)


--
Alan Griffiths (alan.gr...@experian.com, +44 115 934 4517)
Senior Systems Consultant, Experian

Sent via Deja.com http://www.deja.com/
Before you buy.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gabriel Dos Reis

unread,
Mar 20, 2000, 3:00:00 AM3/20/00
to
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> writes:

[...]

| But as I said in another message
|
| template<typename T>
| void swap(P<T>&, P<T>&) { /* ... */ }
|
| is *not* a partial specialization. It is an overloading. Thus
| it can be put put in namespace std, as per the rule quoted above.

^^^^^^^^^^
I meant: "it cannot be put"

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gabriel Dos Reis

unread,
Mar 20, 2000, 3:00:00 AM3/20/00
to
alan_gr...@my-deja.com writes:

[...]

| An alternative is to provide swap<>(Matrix<T>&, Matrix<T>&) in the
| namespace that contains Matrix - but that has problems too. (Think of
| writing code that uses Matrix in a class with a swap() member function.
| Too easy? Try a template class that could be passed Matrix as a
| parameter.)

I think that in such cases, on can use non-member function swap() in
an unqualified manner and let Koenig lookup to do the right thing.

nik...@my-deja.com

unread,
Mar 20, 2000, 3:00:00 AM3/20/00
to
In article <flwvn08...@poivre.cmla.ens-cachan.fr>,

Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote:
> nik...@my-deja.com writes:
>
> | In article <8ankpq$9da$1...@nnrp1.deja.com>,
> | alan_gr...@my-deja.com wrote:
> | > In article <uog8hb...@nonsense.dy.natinst.com>,
> | > Todd Greer <tgr...@acm.org> wrote:
> | > >
> | > > Specializing std templates with user-defined types is explicitly
> | > > allowed. Thus, write:
> | > >
> | > > namespace std
> | > > {
> | > > template<class T>
> | > > void swap(P<T>& a, P<T>& b) {...}
> | > > }
> | >
> | > The code you give _overloads_ the std::swap<> template function.
This
> | > is currently disallowed - although the issue has been discussed
in a
> | > number of forums.
> | Actually, I don't think it's either a partial specialization
> | _or_ an overload, but is simply ambiguous.
>
> ???
>
> 13/1:
> When two or more different declarations are specified for a single
> name in the same scope, that name is said to be overloaded. [...]

Allow me to restate my point without abusing the term overload.
Given the two function declarations,

namespace std {

// The standard version.
template<class T>
void swap(T& arg1, T& arg2);

// The version for my template class.
template<class T>
void swap(MyType<T>& arg1, MyType<T>& arg2);
}

the second function can *never* be called. Attempting to do so
results in abiguity, e.g.,

MyType<int> a;
MyType<int> b;
std::swap(a, b); // ambiguous

Because of this, I mistakenly asserted that the two functions
are not overloaded. It would be more accurate to say that
overloading doesn't solve my problem. That problem once
again is:

How can I write a swap function for my template class
in such a way that my function will always be called
instead of the general-purpose std::swap function.

So far, I am no nearer a solution. In particular, it appears
that the solution used by the boost.org smart pointers is no
solution at all -- even if one is willing to flout the rule
that says you can't overload standard functions in the std
namespace.


Sent via Deja.com http://www.deja.com/
Before you buy.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Thomas Maeder

unread,
Mar 20, 2000, 3:00:00 AM3/20/00
to
Gabriel Dos Reis schrieb:

>
> Why can't you put 'swap(Matrix<>&, Matrix<>&)' in Matrix's namespace
> definition?

Because the option of specializing Standard library classes and functions
was ruled in to provide compile-time specialization.

Say I have this program:

int main()
{
std::vector<int> v1,v2;
// initialization of v1 and v2

std::swap(v1,v2); // ok
}

If I then decide to substitute a container class template of my own for
std::vector, I have to change the call to swap, too. Not nice.

Hyman Rosen

unread,
Mar 21, 2000, 3:00:00 AM3/21/00
to
nik...@my-deja.com writes:
> Given the two function declarations,
> namespace std {
> template<class T>
> void swap(T& arg1, T& arg2);
> template<class T>
> void swap(MyType<T>& arg1, MyType<T>& arg2);
> }
> the second function can *never* be called. Attempting to do so
> results in abiguity, e.g.,
>
> MyType<int> a;
> MyType<int> b;
> std::swap(a, b); // ambiguous

This is false. In 13.3.3 we learn that for a pair of overloaded
function templates, the more specialized one is preferred, and
14.5.5.2 tells us that the second function is more specialized
than the first.

Darin Adler

unread,
Mar 21, 2000, 3:00:00 AM3/21/00
to
In article <8b5o9t$la4$1...@nnrp1.deja.com>, nik...@my-deja.com wrote:

> Allow me to restate my point without abusing the term overload.

> Given the two function declarations,
>
> namespace std {
>

> // The standard version.


> template<class T>
> void swap(T& arg1, T& arg2);
>

> // The version for my template class.

> template<class T>
> void swap(MyType<T>& arg1, MyType<T>& arg2);
> }
>
> the second function can *never* be called. Attempting to do so
> results in abiguity, e.g.,
>
> MyType<int> a;
> MyType<int> b;
> std::swap(a, b); // ambiguous

This is wrong. The version for your template class (an overload of the
standard version) will be called because it's a better match. It is not
ambiguous according to the standard nor according to my compiler.

The relevant part of the standard is 13.3.3/1 says that a template
function that is "more specialized" will win. 14.5.5.2 defines what
"more specialized" means. In this case, the version of swap for your
template class wins.

The only thing wrong with the code above is that the standard explicitly
forbids adding things to namespace std, with an exception for partial
specializations depending on user-defined types. Since the above is an
overload, not a partial specialization it does not qualify for the
exception and the standard forbids it.

-- Darin

Todd Greer

unread,
Mar 21, 2000, 3:00:00 AM3/21/00
to
alan_gr...@my-deja.com writes:

> > template<class T>
> > void swap(P<T>& a, P<T>& b) {...}

> The code you give _overloads_ the std::swap<> template function. This
> is currently disallowed - although the issue has been discussed in a
> number of forums.

Aack! I had thought you could write partial specializations of
template functions, and that I had written one. Thank you for the
correction.

I think allowing partial specialization of functions might be better
than allowing overloading std functions, because it would then be a
small step towards partial member function specialization, and then
Andrei would finally be happy. (I'm not making fun of him--he has
legit reasons.)

If it weren't for the frequency with which someone points out how
wrong I am in my posts, I would know less C++.

--
Todd Greer <tgr...@acm.org>

Jonathan Lundquist

unread,
Mar 21, 2000, 3:00:00 AM3/21/00
to
On 20 Mar 2000 05:50:16 -0500, Gabriel Dos Reis
<dos...@cmla.ens-cachan.fr> wrote:

>
>But as I said in another message
>
> template<typename T>
> void swap(P<T>&, P<T>&) { /* ... */ }
>
>is *not* a partial specialization. It is an overloading. Thus
>it can be put put in namespace std, as per the rule quoted above.

Whatever we call that thing above, can anyone give a good reason why
it isn't allowed in std (besides the standard says so). Is there any
scenario where ambiguities arise provided 'P' is a user defined
template? Is this an oversight in the standard?

>
>There is nothing named *template function partial specialization*.
>The only thing you have with template function is
> o explicit (i.e. full) specialization
> o overloading.
>
>That is all.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Darin Adler

unread,
Mar 21, 2000, 3:00:00 AM3/21/00
to
alan_gr...@my-deja.com writes:

> | An alternative is to provide swap<>(Matrix<T>&, Matrix<T>&) in the
> | namespace that contains Matrix - but that has problems too. (Think of
> | writing code that uses Matrix in a class with a swap() member function.
> | Too easy? Try a template class that could be passed Matrix as a
> | parameter.)

In article <fl7lexz...@poivre.cmla.ens-cachan.fr>, Gabriel Dos Reis
<dos...@cmla.ens-cachan.fr> wrote:

> I think that in such cases, on can use non-member function swap() in
> an unqualified manner and let Koenig lookup to do the right thing.

It's true that non-member function in the same namespace as Matrix is
allowed by the standard, and overloading the swap function in the
standard namespace is not allowed by the standard.

Unfortunately, relying on Koenig lookup in this way means that template
programmers have to use "using" rather than "std::" to get at standard
functions like swap. For example:

template <typename T, typename U>
swap_first_elements (std::pair<T,U>& p, std::pair<T,U>& q) {
std::swap (p.first, q.first);
}

If T has an improved swap in its own namespace, the above function
template will not take advantage of it.

template <typename T, typename U>
swap_first_elements (std::pair<T,U>& p, std::pair<T,U>& q) {
using std::swap;
swap (p.first, q.first);
}

Only this second form will use Koenig lookup.

-- Darin

Andrei Alexandrescu

unread,
Mar 21, 2000, 3:00:00 AM3/21/00
to
<alan_gr...@my-deja.com> wrote in message
news:8b4ua3$2kp$1...@nnrp1.deja.com...

> There are many reasons to want to provide "partial specialisations" of
> the standard algorithms (such as Andrei's Matrix). But it is not
> allowed by the language - the obvious alternative of overloading in
> namespace std is better (only "undefined behavior") but not ideal.

If this is true, I think someone should file a Defect Report.

I certainly expect that when I call std::swap(a, b) to swap the two
elements. Some STL algorithms expect this, too. If a class does not support
efficient swapping with the stock algorithm (T temp(lhs); lhs = rhs; rhs =
temp), then it is that class' responsibility to fiddle with std::swap.

Forbidding partial ordering or overloading or whatever you call it for
std::swap makes it practically impossible for template class writers to
provide appropriate std::swap semantics.

I am also certain the Standard *does* intend to give programmers and library
writers this opportunity.

Therefore, I think a defect report should be submitted.

> An alternative is to provide swap<>(Matrix<T>&, Matrix<T>&) in the
> namespace that contains Matrix - but that has problems too.

I don't think that's even an option. Client code may call std::swap
explicitly, and I don't think that's an error.

> Look at the current thread - the participants are all
> "above average" in their knowledge and interest in standard C++.

A good means to attract people to this thread :o).


Andrei

Gabriel Dos Reis

unread,
Mar 21, 2000, 3:00:00 AM3/21/00
to
Thomas Maeder <mae...@glue.ch> writes:

| Gabriel Dos Reis schrieb:
| >
| > Why can't you put 'swap(Matrix<>&, Matrix<>&)' in Matrix's namespace
| > definition?
|
| Because the option of specializing Standard library classes and functions
| was ruled in to provide compile-time specialization.
|
| Say I have this program:
|
| int main()
| {
| std::vector<int> v1,v2;
| // initialization of v1 and v2
|
| std::swap(v1,v2); // ok
| }
|
| If I then decide to substitute a container class template of my own for
| std::vector, I have to change the call to swap, too.

Not if you just said:

swap(v1, v2);

Koenig lookup will take care of you.

Writing "std::swap" is strong a requirement -- as any form of
qualified-id use. If you want flexible programms, then you have to be
flexible in your requirements.

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

alan_gr...@my-deja.com

unread,
Mar 21, 2000, 3:00:00 AM3/21/00
to
In article <8b5o9t$la4$1...@nnrp1.deja.com>,
nik...@my-deja.com wrote:
>
> namespace std {
>
> // The standard version.
> template<class T>
> void swap(T& arg1, T& arg2);
>
> // The version for my template class.
> template<class T>
> void swap(MyType<T>& arg1, MyType<T>& arg2);
> }

If, for example, you substitute std::vector for "MyType" this is exactly
what the standard library does.

> the second function can *never* be called. Attempting to do so
> results in abiguity, e.g.,

No it doesn't - see 14.5.5.2. I suspect you have encountered a compiler
bug.

--
Alan Griffiths (alan.gr...@experian.com, +44 115 934 4517)
Senior Systems Consultant, Experian

Sent via Deja.com http://www.deja.com/
Before you buy.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

alan_gr...@my-deja.com

unread,
Mar 21, 2000, 3:00:00 AM3/21/00
to
> alan_gr...@my-deja.com writes:
>
> [...]

>
> | An alternative is to provide swap<>(Matrix<T>&, Matrix<T>&) in the
> | namespace that contains Matrix - but that has problems too. (Think
of
> | writing code that uses Matrix in a class with a swap() member
function.
> | Too easy? Try a template class that could be passed Matrix as a
> | parameter.)
>
> I think that in such cases, on can use non-member function swap() in
> an unqualified manner and let Koenig lookup to do the right thing.

No you can't - note "in a class with a swap() member function". (You'll
probably get a compile error).

The obvious (but wrong) approach is to add "using std::swap".

The right approach in the generic case is to use a _non-member_ function
in your library that looks like:

template<typename type>
inline name_dependent_swap(type& lhs, type& rhs)
{
using std::swap;
swap(lhs, rhs);
}

But remember - the "you" here isn't the author of Matrix - it is every
author of a template class that _might_ be used with Matrix.

(And, of course, the problem applies to find<> and other algorithms, not
just swap.)

Requiring every author to successfully jump this hoop is unrealistic.

Gabriel Dos Reis

unread,
Mar 21, 2000, 3:00:00 AM3/21/00
to
nik...@my-deja.com writes:

[...]

| Allow me to restate my point without abusing the term overload.
| Given the two function declarations,
|

| namespace std {
|
| // The standard version.
| template<class T>
| void swap(T& arg1, T& arg2);
|
| // The version for my template class.
| template<class T>
| void swap(MyType<T>& arg1, MyType<T>& arg2);

As said in another message, this may result in undefined behaviour.
But let's assume it won't.

| }
|
| the second function can *never* be called.

I, still, can't see any reason that supports this claim.

| ... Attempting to do so
| results in abiguity, e.g.,
|

| MyType<int> a;
| MyType<int> b;
| std::swap(a, b); // ambiguous

Why?

Template argument deduction yields:

o swap<MyType<int> >(MyType<int>&, MyType<int>&)
o swap<int>(MyType<int>&, MyType<int>&)


Now, partial ordering (14.5.5.2) says that the function template

template<typename T> swap(MyType<T>&, MyType<T>&)

is more specialized than

template<typename T> swap(T&, T&)

so swap<int>(MyType<T>&, MyType<T>&) should be selected.

Am I overlooking something?

| Because of this, I mistakenly asserted that the two functions
| are not overloaded. It would be more accurate to say that
| overloading doesn't solve my problem. That problem once
| again is:
|
| How can I write a swap function for my template class
| in such a way that my function will always be called
| instead of the general-purpose std::swap function.

Just put it in the namespace of your class template definition.

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gabriel Dos Reis

unread,
Mar 22, 2000, 3:00:00 AM3/22/00
to
Darin Adler <da...@bentspoon.com> writes:

[...]

| Only this second form will use Koenig lookup.

Yes, you made a good summary of the situation.

Personnally, I think that calling a function through a qualified-id in
an unknown context is strong a requirement. In heavy template-based
code I thing that using-declarations and Koenig lookup do provide an
extremely flexible device.

Gabriel Dos Reis

unread,
Mar 22, 2000, 3:00:00 AM3/22/00
to
"Andrei Alexandrescu" <andre...@hotmail.com> writes:

| <alan_gr...@my-deja.com> wrote in message
| news:8b4ua3$2kp$1...@nnrp1.deja.com...
| > There are many reasons to want to provide "partial specialisations" of
| > the standard algorithms (such as Andrei's Matrix). But it is not
| > allowed by the language - the obvious alternative of overloading in
| > namespace std is better (only "undefined behavior") but not ideal.
|
| If this is true, I think someone should file a Defect Report.
|
| I certainly expect that when I call std::swap(a, b) to swap the two
| elements. Some STL algorithms expect this, too. If a class does not support
| efficient swapping with the stock algorithm (T temp(lhs); lhs = rhs; rhs =
| temp), then it is that class' responsibility to fiddle with std::swap.

Not necessarily std::swap. It suffices it provides swap(). The
language has the necessary mechanics to select the right function.
Assuming of course that that mechanics are used appropriately.

| Forbidding partial ordering or overloading or whatever you call it for
| std::swap makes it practically impossible for template class writers to
| provide appropriate std::swap semantics.

No, they can. Koenig lookup is there to solve such problems.

Gabriel Dos Reis

unread,
Mar 22, 2000, 3:00:00 AM3/22/00
to
alan_gr...@my-deja.com writes:

| In article <fl7lexz...@poivre.cmla.ens-cachan.fr>,
| Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote:
| > alan_gr...@my-deja.com writes:
| >
| > [...]
| >
| > | An alternative is to provide swap<>(Matrix<T>&, Matrix<T>&) in the
| > | namespace that contains Matrix - but that has problems too. (Think
| of
| > | writing code that uses Matrix in a class with a swap() member
| function.
| > | Too easy? Try a template class that could be passed Matrix as a
| > | parameter.)
| >
| > I think that in such cases, on can use non-member function swap() in
| > an unqualified manner and let Koenig lookup to do the right thing.
|
| No you can't - note "in a class with a swap() member function". (You'll
| probably get a compile error).

Well, perhaps I was unclear but I suggesting to define a non-member
function as you describe in the rest of your message.

| The obvious (but wrong) approach is to add "using std::swap".
|
| The right approach in the generic case is to use a _non-member_ function
| in your library that looks like:
|
| template<typename type>
| inline name_dependent_swap(type& lhs, type& rhs)
| {
| using std::swap;
| swap(lhs, rhs);
| }

This is exactly what I suggested on the boost list reflector when we
were discussing abs() for a template rational class.

| But remember - the "you" here isn't the author of Matrix - it is every
| author of a template class that _might_ be used with Matrix.
|
| (And, of course, the problem applies to find<> and other algorithms, not
| just swap.)
|
| Requiring every author to successfully jump this hoop is unrealistic.

As unrealistic as to require every author of template library to learn
about template and the two-phase name lookup mechanics (or at least to
be competent)?

nik...@my-deja.com

unread,
Mar 22, 2000, 3:00:00 AM3/22/00
to
In article <fl66ugv...@pizza.cmla.ens-cachan.fr>,

Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote:
> nik...@my-deja.com writes:
>
> [...]
>
> | Allow me to restate my point without abusing the term overload.
> | Given the two function declarations,
> |
> | namespace std {
> |
> | // The standard version.
> | template<class T>
> | void swap(T& arg1, T& arg2);
> |
> | // The version for my template class.
> | template<class T>
> | void swap(MyType<T>& arg1, MyType<T>& arg2);
>
> As said in another message, this may result in undefined behaviour.
> But let's assume it won't.

Agreed on both counts.

> | }
> |
> | the second function can *never* be called.
>
> I, still, can't see any reason that supports this claim.
>
> | ... Attempting to do so
> | results in abiguity, e.g.,
> |
> | MyType<int> a;
> | MyType<int> b;
> | std::swap(a, b); // ambiguous
>
> Why?
>
> Template argument deduction yields:
>
> o swap<MyType<int> >(MyType<int>&, MyType<int>&)
> o swap<int>(MyType<int>&, MyType<int>&)

Yes.

>
> Now, partial ordering (14.5.5.2) says that the function template
>
> template<typename T> swap(MyType<T>&, MyType<T>&)
>
> is more specialized than
>
> template<typename T> swap(T&, T&)
>
> so swap<int>(MyType<T>&, MyType<T>&) should be selected.
>
> Am I overlooking something?

This is the part I'm questioning, but I don't really understand
the partial ordering rules so I may be wrong. Let me try to
break it down into steps.

Section 14.5.5.2 paragraphs 2-3 say the two function templates
are transformed as follows:

; Replace T with MyType<int> in first template.
swap(MyType<int>&, MyType<int>&);

; Replace T with int in second template.
swap(MyType<int>&, MyType<int>&);

Next paragraph 4 has us perform argument deduction for each
template against the parameter list of the opposite function.
Because both succeed without requiring any type conversions
we conclude that each template is at least as specialized as
the other; therefore (paragraph 5) neither is more specialized
than the other.

I realize examples are non-normative, but the example in
this section seems to reinforce the above analysis:

...


template<class T> void h(const T&);
template<class T> void h(A<T>&);

...
h(z); // overload resolution selects h(A<T>&)

...

The comment implies that neither function template is
"more specialized" than the other; the call would be
amgiguous except that overload resolution selects the
function that takes a non-const reference.

> | Because of this, I mistakenly asserted that the two functions
> | are not overloaded. It would be more accurate to say that
> | overloading doesn't solve my problem. That problem once
> | again is:
> |
> | How can I write a swap function for my template class
> | in such a way that my function will always be called
> | instead of the general-purpose std::swap function.
>
> Just put it in the namespace of your class template definition.

But will Koenig lookup find my version of swap if the caller
uses an explicit namespace qualifer as in the above example?


Sent via Deja.com http://www.deja.com/
Before you buy.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

alan_gr...@my-deja.com

unread,
Mar 22, 2000, 3:00:00 AM3/22/00
to
In article <fln1ntu...@pizza.cmla.ens-cachan.fr>,

Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote:
> Thomas Maeder <mae...@glue.ch> writes:
>
> | Gabriel Dos Reis schrieb:
> | >
> | > Why can't you put 'swap(Matrix<>&, Matrix<>&)' in Matrix's
namespace
> | > definition?
> |
> | Because the option of specializing Standard library classes and
functions
> | was ruled in to provide compile-time specialization.
> |
> | Say I have this program:
> |
> | int main()
> | {
> | std::vector<int> v1,v2;
> | // initialization of v1 and v2
> |
> | std::swap(v1,v2); // ok
> | }

A better example (because it prevents Gabriel's solution) is:

struct example
{
std::vector<int> v;

void swap(example& that) // Swap this and that
{
std::swap(v, that.v); // OK
}
};

> |
> | If I then decide to substitute a container class template of my own
for
> | std::vector, I have to change the call to swap, too.

Exactly.

> Not if you just said:
>
> swap(v1, v2);

In the revised example name lookup only finds example::swap() - which
causes a compile error.

> Koenig lookup will take care of you.

Not in the revised example.

The right approach is:

template<typename type>
inline name_dependent_swap(type& lhs, type& rhs)
{
using std::swap;
swap(lhs, rhs);
}


struct example
{
std::vector<int> v;

void swap(example& that) // Swap this and that
{
name_dependent_swap(v, that.v);
}
};

--
Alan Griffiths (alan.gr...@experian.com, +44 115 934 4517)
Senior Systems Consultant, Experian

Dave Abrahams

unread,
Mar 22, 2000, 3:00:00 AM3/22/00
to
in article fl66ugv...@pizza.cmla.ens-cachan.fr, Gabriel Dos Reis at
dos...@cmla.ens-cachan.fr wrote on 3/21/00 12:24 PM:

> | How can I write a swap function for my template class
> | in such a way that my function will always be called
> | instead of the general-purpose std::swap function.
>
> Just put it in the namespace of your class template definition.

Really that depends on how algorithm implementors decide to respond to the
unfortunate dilemma given to us by whoever designed this part of the
language. There are several possible choices:

1. Just use unqualified swap() and rely on Koenig lookup to find the right
version. This effectively reserves the name "swap" in ALL namespaces. If
someone should write a 2-argument swap function with different semantics
(admittedly unlikely, but think of copy or some of the other standard
algorithms), the standard algorithms would be broken.

2. Use qualified std::swap() and be sure that you're getting the right
semantics. Actually, the only place the standard mentions using swap for an
algorithm is in the reverse() algorithm, and even there it seems rather
unclear whether the intention is to use Koenig lookup or not.

3. Don't use swap at all. Probably OK for everything but reverse().

-Dave

Carl Barron

unread,
Mar 23, 2000, 3:00:00 AM3/23/00
to
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote:

> Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> writes:
>
> [...]
>

> | But as I said in another message
> |
> | template<typename T>
> | void swap(P<T>&, P<T>&) { /* ... */ }
> |
> | is *not* a partial specialization. It is an overloading. Thus
> | it can be put put in namespace std, as per the rule quoted above.

> ^^^^^^^^^^
> I meant: "it cannot be put"

Well what does your <vector> file do to define swap for vectors??
I'd bet it says something like:

template <class T,class A>
void swap(vector<T,A> &,vector<T,A> & y) {x.swap(y);}

mine does (CWP 5.3). If this is valid for vector's why not any other
templated class with a swap member function?

namespaces are open, therefore almoost anything can be put into
namespace std, but its not standard to polute the std namespace.

alan_gr...@my-deja.com

unread,
Mar 23, 2000, 3:00:00 AM3/23/00
to
In article <fl66ugp...@pizza.cmla.ens-cachan.fr>,

Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote:
>
> As unrealistic as to require every author of template library to learn
> about template and the two-phase name lookup mechanics (or at least to
> be competent)?

But it is not just authors of template libraries that are affected. (I
might not like the situation - but at least you and I understand it.) On
this thread there has been an example of the problem impacting code
maintenance in a non-template class, and a people indicating the desire
that typing in client code std::swap resolve to the "correct" version.

IMO if the library working group had understood the implications of the
current rules then they would have supplied a standard implementation of
the forwarding non-member function templates.

I admit that allowing overloading of the standard algorithms (such as
swap<>) based on a user defined name does have theoretical problems.
For example, if we allow:


// No _I_ wouldn't put it in global namespace - but bear with me
template<typename element>
class heap;

namespace std {
template<typename element>
swap(heap<element>&, heap<element>&) { ... }
}

What happens when the committee decides to add std::heap in a future
version of C++?

There is a problem - you have taken the reasonable position that the
resolution is by education. I don't believe that is adequate.


-
Alan Griffiths (alan.gr...@experian.com, +44 115 934 4517)
Senior Systems Consultant, Experian


Sent via Deja.com http://www.deja.com/
Before you buy.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Siemel B. Naran

unread,
Mar 23, 2000, 3:00:00 AM3/23/00
to
On 21 Mar 2000 11:50:41 -0500, Gabriel Dos Reis

>Not if you just said:
>
> swap(v1, v2);
>

>Koenig lookup will take care of you.

Good.


>Writing "std::swap" is strong a requirement -- as any form of
>qualified-id use. If you want flexible programms, then you have to be
>flexible in your requirements.

Good.


If the builtin types lived in namespace std then I would agree with
you 100%. But at the present time, I agree with you 96%.

namespace enhanced {
template <class Iter>
void rapidsort(Iter begin, Iter end) { /*use swap(*begin,*end)*/ }
}

If Iter::value_type is any type in namespace std, then the call to
swap(*begin,*end) automatically looks in namespace std for the
definition of swap and finds it.

If Iter::value_type is any type in namespace myspace and we have
taken care to declare myspace::swap(...), then the call to
swap(*begin,*end) automatically looks in namespace myspace for the
definition of swap and finds it.

But if Iter::value_type is a fundamental type, then the unqualified
call to swap(*begin,*end) fails to find the declaration of swap.


Solution 1: Define the fundamental types (double, int, ...) in
namespace std.

Solution 2: Define explicit functions ::swap(int,int), etc.

--
--------------
siemel b naran
--------------

Siemel B. Naran

unread,
Mar 23, 2000, 3:00:00 AM3/23/00
to
On 22 Mar 2000 09:50:17 -0500, alan_gr...@my-deja.com

>A better example (because it prevents Gabriel's solution) is:
>
> struct example
> {
> std::vector<int> v;
>
> void swap(example& that) // Swap this and that
> {
> std::swap(v, that.v); // OK
> }
> };

The "std::" is not necessary and ill-advised.
Koenig lookup says to look in the namespace where "this->v" and
"that.v" live to find the definition of swap. This namespace is
"std::".

Siemel B. Naran

unread,
Mar 23, 2000, 3:00:00 AM3/23/00
to
On 23 Mar 2000 04:11:11 -0500, Carl Barron <cbar...@ix.netcom.com> wrote:
>Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote:

>> But as I said in another message
>>
>> template<typename T>
>> void swap(P<T>&, P<T>&) { /* ... */ }
>>
>> is *not* a partial specialization. It is an overloading. Thus

>> it cannot be put in namespace std, as per the rule quoted above.

> Well what does your <vector> file do to define swap for vectors??
> I'd bet it says something like:
>
> template <class T,class A>
> void swap(vector<T,A> &,vector<T,A> & y) {x.swap(y);}
>
> mine does (CWP 5.3). If this is valid for vector's why not any other
>templated class with a swap member function?

It is not necessary to put the definition of swap in namespace std,
thanks to Koenig lookup. Just do

namespace enhanced {
template <class T> class Matrix { ... };
template <class T>
void swap(Matrix<T>& lhs, Matrix<T>& rhs) { lhs.swap(rhs); }
}

int main() { enhanced::Matrix<int> M1,M2; swap(M1,M2); }

The call to swap looks in the namespace where M1 and M2 live for the
definition of swap. Thus it finds enhanced::swap(...).


> namespaces are open, therefore almoost anything can be put into
>namespace std, but its not standard to polute the std namespace.

The rule that you ought not to put your specializations in namespace
std is good because it's not good to open up someone else's library
and fiddle around with it. As the author of namespace enhanced, I
forbid anyone to specialize any of my classes.


But the other question remains -- what is the difference between a
template specialization and overloading? To my mind, they really
are the same thing.

Darin Adler

unread,
Mar 24, 2000, 3:00:00 AM3/24/00
to
In article <1e7so19.jw...@buf-ny10-99.ix.netcom.com>,
cbar...@ix.netcom.com (Carl Barron) wrote:

> Well what does your <vector> file do to define swap for vectors??
> I'd bet it says something like:
>
> template <class T,class A>
> void swap(vector<T,A> &,vector<T,A> & y) {x.swap(y);}
>
> mine does (CWP 5.3). If this is valid for vector's why not any other
> templated class with a swap member function?

Because vector is part of the standard library. This specialization is
required by the standard. That doesn't guarantee that you can do it for
your own classes.

> namespaces are open, therefore almoost anything can be put into
> namespace std, but its not standard to polute the std namespace.

I don't know what you mean when you say it "can be put" in std. Yes, the
compiler and library you have might allow it, and it might have
predictable behavior. But the standard explicitly forbids it, so it
isn't guaranteed to work at all with other compilers or library
implementations.

-- Darin

Darin Adler

unread,
Mar 24, 2000, 3:00:00 AM3/24/00
to
In article <8bd2o7$j1h$1...@nnrp1.deja.com>, alan_gr...@my-deja.com
wrote:

> I admit that allowing overloading of the standard algorithms (such as
> swap<>) based on a user defined name does have theoretical problems.
> For example, if we allow:
>
> // No _I_ wouldn't put it in global namespace - but bear with me
> template<typename element>
> class heap;
>
> namespace std {
> template<typename element>
> swap(heap<element>&, heap<element>&) { ... }
> }
>
> What happens when the committee decides to add std::heap in a future
> version of C++?

This can be resolved; unfortunately, it's "by education" also:

template<typename element>
class heap;

namespace std {
template<typename element>

swap(::heap<element>&, ::heap<element>&) { ... }
}

You've got to be on your best behavior when visiting namespace std.

Lisa Lippincott

unread,
Mar 24, 2000, 3:00:00 AM3/24/00
to
Alan Griffiths <alan_gr...@my-deja.com> volunteers:
> I'm not the only one that knowingly relies on "undefined behavior" in
> this area - check out the boost smart pointers (http://www.boost.org/).
> AFAIK there is no ideal solution in the language as currently defined.
> When I can work out what the standard should say I'll submit a defect
> report. (But this isn't easy either.)

I'll give you a push. Here's the insufficient part of the standard,
from 17.4.3.1 [lib.reserved.names]:

A program may add template specializations for any standard
library template to namespace std. Such a specialization
(complete or partial) of a standard library template results
in undefined behavior unless the declaration depends on a
user-defined name of external linkage and unless the specialization
meets the standard library requirements for the original template.

To me, the limits provided by this passage seem adequate for overloading.
I suggest adding:

A program may add to namespace std function template declarations
which overload any standard library function template name. Such
declarations result in undefined behavior unless the declaration
depends on a user-defined name of external linkage and unless the
function template meets the standard library requirements for
the original template.

More boldly, I suggest allowing overloading for non-template functions
as well. This would be a real boon in numeric programming, allowing
the function names in 26.5 [lib.c.math] to be used for user-defined
numeric types, in addition to int, long, float, and double.

Here's a more expansive wording:

A program may add to namespace std function or function template
declarations which overload any standard library function or
function template name. Such declarations result in undefined
behavior unless the declaration depends on a user-defined name of
external linkage and unless the function or function template
meets the standard library requirements for the original function
or function template.

Since a careful programmer will use a fully-qualified "user-defined name
of external linkage," lest it become standard-defined in the future.
It may be a good idea to add that adjective to both the old and the new
wording.

How does this wording sound?
--Lisa Lippincott

Andrei Alexandrescu

unread,
Mar 24, 2000, 3:00:00 AM3/24/00
to
Siemel B. Naran <sbn...@uiuc.edu> wrote in message
news:slrn8dkbp5....@localhost.localdomain...

[snip all]

You are 96% happy, but I'm still not satisfied.

My question is: what's easier?

1. Give someone a library and just ask them to call std algorithms with the
objects of your types as they always did. That is, you define a class BigNum
and they can call std::swap(a, b) for a and b being two BigNums. I find this
a simple and intuitive rule.

2. Give someone a library and tell them they must use the following idiom:

{
BigNum a;
using std::some_algorithm;
some_algorithm(a);
}

in *every* darn place they ever use a standard algorithm on any of your
types.

I don't think you can convince me easily that (2) is preferrable.

What's worse about (2) is that, in particular for swap, reckless users will
not be flagged by the compiler. If BigNum has value semantics (as it
should), then std::swap will work on it, but very inefficiently.

Now we live in a wonderful world:

a) Savvy users will use the correct, verbose, ugly, deplorable, hateable
idiom (2) and will get efficient programs.

b) Plebeian users (as I have to humbly submit I am - I always thought you
can and should overload std::algorithms for your types appropriately) will
write code that uses std::swap explicitly, the compiler will not say a
thing, and their programs will work, but slower.

Same story goes about, for instance, std::copy. If a library defines a POD
and a bit-blasting copy in that library's namespace, users who call
std::copy on pointers to those PODs will get the program working, only
slower.

I find this sad. I'm not a namespace expert, and now that I discovered some
details I'd say, ignorance is bliss.

There's one more thing I don't like about this thread - the attitude that
the Standard is perfect and that any criticism to it is an insult. I don't
like being a yesman. I don't like how namespaces work, and you cannot prove
me how nice they are just because they are standard. It just happens, even
some of the people who helped with *defining* namespaces don't like how they
work and admit they are... here degree of appreciation varies from imperfect
to flawed to broken.


Andrei

Gabriel Dos Reis

unread,
Mar 24, 2000, 3:00:00 AM3/24/00
to
alan_gr...@my-deja.com writes:

| In article <fln1ntu...@pizza.cmla.ens-cachan.fr>,


| Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote:

| > Thomas Maeder <mae...@glue.ch> writes:
| >
| > | Gabriel Dos Reis schrieb:
| > | >
| > | > Why can't you put 'swap(Matrix<>&, Matrix<>&)' in Matrix's
| namespace
| > | > definition?
| > |
| > | Because the option of specializing Standard library classes and
| functions
| > | was ruled in to provide compile-time specialization.
| > |
| > | Say I have this program:
| > |
| > | int main()
| > | {
| > | std::vector<int> v1,v2;
| > | // initialization of v1 and v2
| > |
| > | std::swap(v1,v2); // ok
| > | }
|

| A better example (because it prevents Gabriel's solution) is:
|
| struct example
| {
| std::vector<int> v;
|
| void swap(example& that) // Swap this and that
| {
| std::swap(v, that.v); // OK
| }
| };
|
| > |

| > | If I then decide to substitute a container class template of my own
| for
| > | std::vector, I have to change the call to swap, too.
|
| Exactly.
|

| > Not if you just said:
| >
| > swap(v1, v2);
|

| In the revised example name lookup only finds example::swap() - which
| causes a compile error.

Could you explain why?


3.4.2/2 implies that lookup will find std::swap.

| > Koenig lookup will take care of you.
|

| Not in the revised example.

Even in the revised example. Or you have to revise your revised
example :-)

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gabriel Dos Reis

unread,
Mar 24, 2000, 3:00:00 AM3/24/00
to
Jonathan Lundquist <j...@sssonline.com> writes:

| On 20 Mar 2000 05:50:16 -0500, Gabriel Dos Reis


| <dos...@cmla.ens-cachan.fr> wrote:
|
| >
| >But as I said in another message
| >
| > template<typename T>
| > void swap(P<T>&, P<T>&) { /* ... */ }
| >
| >is *not* a partial specialization. It is an overloading. Thus

| >it can be put put in namespace std, as per the rule quoted above.
|
| Whatever we call that thing above, can anyone give a good reason why
| it isn't allowed in std (besides the standard says so). Is there any
| scenario where ambiguities arise provided 'P' is a user defined
| template? Is this an oversight in the standard?

I think the rationale is that any name found by lookup in std:: is
guaranteed to be defined either by the standard or the implementation
(this expresses the reserved nature of std).

But I wasn't there when that rule was voted in.

Gabriel Dos Reis

unread,
Mar 24, 2000, 3:00:00 AM3/24/00
to
alan_gr...@my-deja.com writes:

| In article <fl66ugp...@pizza.cmla.ens-cachan.fr>,


| Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote:
| >

| > As unrealistic as to require every author of template library to learn
| > about template and the two-phase name lookup mechanics (or at least to
| > be competent)?
|
| But it is not just authors of template libraries that are affected. (I
| might not like the situation - but at least you and I understand it.) On
| this thread there has been an example of the problem impacting code
| maintenance in a non-template class, and a people indicating the desire
| that typing in client code std::swap resolve to the "correct" version.

I do understand the desire to overload function template in std.
But I think the main issue is user education. I think they got there
because of a particular design of their program. The first thing we
need to address is whether that design can be corrected.

| IMO if the library working group had understood the implications of the
| current rules then they would have supplied a standard implementation of
| the forwarding non-member function templates.
|

| I admit that allowing overloading of the standard algorithms (such as
| swap<>) based on a user defined name does have theoretical problems.

But we need to reserve a namespace for future extension. One simple
way to acheive that is to put in a rule that guarantee that any name
found by lookup in std:: is defined either by the standard or the
implementation. That is what the current rule does.

| For example, if we allow:
|
|
| // No _I_ wouldn't put it in global namespace - but bear with me
| template<typename element>
| class heap;
|
| namespace std {
| template<typename element>
| swap(heap<element>&, heap<element>&) { ... }
| }
|
| What happens when the committee decides to add std::heap in a future
| version of C++?
|

| There is a problem - you have taken the reasonable position that the
| resolution is by education. I don't believe that is adequate.

Well, I think this is a topic on which reasonable people can disagree.
And I do understand your point of view. I just happen to be
unconvinced that the rule should be changed.

Gabriel Dos Reis

unread,
Mar 24, 2000, 3:00:00 AM3/24/00
to
nik...@my-deja.com writes:

[...]

| >
| > Now, partial ordering (14.5.5.2) says that the function template
| >
| > template<typename T> swap(MyType<T>&, MyType<T>&)
| >
| > is more specialized than
| >
| > template<typename T> swap(T&, T&)
| >
| > so swap<int>(MyType<T>&, MyType<T>&) should be selected.
| >
| > Am I overlooking something?
|
| This is the part I'm questioning, but I don't really understand
| the partial ordering rules so I may be wrong. Let me try to
| break it down into steps.
|
| Section 14.5.5.2 paragraphs 2-3 say the two function templates
| are transformed as follows:
|
| ; Replace T with MyType<int> in first template.
| swap(MyType<int>&, MyType<int>&);
|
| ; Replace T with int in second template.
| swap(MyType<int>&, MyType<int>&);

No. That is not what 14.5.5.2/[2-3] say.
Consider:
1) template<typename T> void swap(T&, T&);
2) template<typename T> void swpa(MyType<T>&, MyType<T>&)

In the first template, replace T with unique_type (where unique_type
is a unique type). Now attempt template argument deduction for the
second template against the parameter list (unique_type&, unique_type&).
That argument deduction fails. So the first template is *not* at
least as specialized as the second.

Repeat the same process in the reverse way. Here argument deduction
for the first template against (MyType<unique_type>&, MyType<unique_type>&)
succeeds. So the second template is at least as specialized as the
first. It follows from 14.5.5.2/5 that the second template is more
specialized than the first. So swap<int>(MyType<int>&, MyType<int>&)
is selected.

[...]

| I realize examples are non-normative, but the example in
| this section seems to reinforce the above analysis:
|

| ...


| template<class T> void h(const T&);
| template<class T> void h(A<T>&);
| ...
| h(z); // overload resolution selects h(A<T>&)
| ...
|
| The comment implies that neither function template is
| "more specialized" than the other;

Right.

| ... the call would be


| amgiguous except that overload resolution selects the
| function that takes a non-const reference.

This is just an example where partial ordering that doesn't help
because not applicable.

|
| > | Because of this, I mistakenly asserted that the two functions
| > | are not overloaded. It would be more accurate to say that
| > | overloading doesn't solve my problem. That problem once
| > | again is:
| > |

| > | How can I write a swap function for my template class
| > | in such a way that my function will always be called
| > | instead of the general-purpose std::swap function.
| >
| > Just put it in the namespace of your class template definition.
|

| But will Koenig lookup find my version of swap if the caller
| uses an explicit namespace qualifer as in the above example?

No. Koenig lookup works only for unqualified-id.

Darin Adler

unread,
Mar 25, 2000, 3:00:00 AM3/25/00
to
In article <230320001820066212%lisa_li...@bigfix.com>, Lisa
Lippincott <lisa_li...@bigfix.com> wrote:

> How does this wording sound?

Sounds great to me.

But the more expansive version that allows overloading even non-template
functions seems that it could be a bit dangerous and I suggest we omit
that if submitting a defect report. Howard Hinnant at Metrowerks may
have some wisdom to impart about his experiences with overloading and
<math.h>; I seem to recall that adding additional signatures created all
sorts of strange incompatibilities.

-- Darin

Andrei Alexandrescu

unread,
Mar 25, 2000, 3:00:00 AM3/25/00
to
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
news:flzorod...@poivre.cmla.ens-cachan.fr...

> I think the rationale is that any name found by lookup in std:: is
> guaranteed to be defined either by the standard or the implementation
> (this expresses the reserved nature of std).

What about partial/total specialization of classes in std:: for user-defined
types, then? Is that an "exception to the reserved nature of std"?


Andrei

Andrei Alexandrescu

unread,
Mar 25, 2000, 3:00:00 AM3/25/00
to
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
news:flvh2cd...@poivre.cmla.ens-cachan.fr...

> I do understand the desire to overload function template in std.
> But I think the main issue is user education. I think they got there
> because of a particular design of their program. The first thing we
> need to address is whether that design can be corrected.

Sure. "Hey, users, don't do what's intuitive and terse. Instead, litter your
code with 'using std::whatever' and then call unqualified whatever()
whenever you need. Otherwise, your design is broken. By definition."

> Well, I think this is a topic on which reasonable people can disagree.
> And I do understand your point of view. I just happen to be
> unconvinced that the rule should be changed.

I can see you're not convinced, but on what ground? All I can see is that
you can't find any major problem, yet you just sustain the current rule is
good and people must be educated.

Andrei Alexandrescu

unread,
Mar 25, 2000, 3:00:00 AM3/25/00
to
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
news:flr9d0d...@poivre.cmla.ens-cachan.fr...

> Consider:
> 1) template<typename T> void swap(T&, T&);
> 2) template<typename T> void swpa(MyType<T>&, MyType<T>&)
>
> In the first template, replace T with unique_type (where unique_type
> is a unique type). Now attempt template argument deduction for the
> second template against the parameter list (unique_type&, unique_type&).
> That argument deduction fails. So the first template is *not* at
> least as specialized as the second.
>
> Repeat the same process in the reverse way. Here argument deduction
> for the first template against (MyType<unique_type>&,
MyType<unique_type>&)
> succeeds. So the second template is at least as specialized as the
> first. It follows from 14.5.5.2/5 that the second template is more
> specialized than the first. So swap<int>(MyType<int>&, MyType<int>&)
> is selected.

Basically you prove here that overloading std:: algorithms for user-defined
types is not dangerous and does not engender any problem at all.

Siemel B. Naran

unread,
Mar 25, 2000, 3:00:00 AM3/25/00
to
On 24 Mar 2000 18:04:48 -0500, Andrei Alexandrescu <andre...@hotmail.com>

>My question is: what's easier?
>
>1. Give someone a library and just ask them to call std algorithms with the
>objects of your types as they always did. That is, you define a class BigNum
>and they can call std::swap(a, b) for a and b being two BigNums. I find this
>a simple and intuitive rule.

No, they should just call 'swap(a,b)'.


>Same story goes about, for instance, std::copy. If a library defines a POD
>and a bit-blasting copy in that library's namespace, users who call
>std::copy on pointers to those PODs will get the program working, only
>slower.

They should call 'copy(...)' or 'sort(...)'.
Koenig lookup will determine whether to use std:: or enhanced:: or whatever.

Some interesting points:

1.
Notice that declaring a function with the same name in different namespaces
is actually a form of overloading, thanks to Koenig lookup. Example:
namespace A { class a { }; void action(a); }
namespace B { class b { }; void action(b); }
int main() { A::a a; B::b b; action(a); action(b); }
The idea that namespaces are decoupled from each other (ie, the symbols in
namespace A have nothing to do with the symbols in namespace B) holds only
for variables and typenames, not functions. Perhaps the distinction is
sound; perhaps it is not.

2.
Try this analogy. Can we overload functions across the inheritance
hierarchy? Yes, if the function is virtual.
struct A { virtual void f(); }
struct B : A { virtual void f(); }
struct C : B { virtual void f(); }
void silly(B& b) { b.f(); }
The "b.f()" calls either B::f or C::f. But when we call explicitly through
the scope resolution operator, as in "b.A::f()" or "b.B::f()", we turn the
virtual function mechanism off, thereby forcing a call to a specific f().
Similarly, when we prepend the namespace 'std::', we force a call to a
function in a specific namespace, thereby turning the namespace overloading
mechanism (ie, Koenig lookup) off.

3.
For this to work flawlessly, the builtin types should be in namespace std.
int array[3]={1,3,2};
sort(array,array+3); // error or ok?
The call to sort(...) is an error in the current rules. But if "int *"
were in namespace std, then the call is ok.

--
--------------
siemel b naran
--------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Thomas Maeder

unread,
Mar 25, 2000, 3:00:00 AM3/25/00
to
"Siemel B. Naran" wrote:
>
> namespace enhanced {
> template <class Iter>
> void rapidsort(Iter begin, Iter end) { /*use swap(*begin,*end)*/ }
> }
>
> If Iter::value_type is any type in namespace std, then the call to
> swap(*begin,*end) automatically looks in namespace std for the
> definition of swap and finds it.
>
> If Iter::value_type is any type in namespace myspace and we have
> taken care to declare myspace::swap(...), then the call to
> swap(*begin,*end) automatically looks in namespace myspace for the
> definition of swap and finds it.
>
> But if Iter::value_type is a fundamental type, then the unqualified
> call to swap(*begin,*end) fails to find the declaration of swap.
>
> Solution 1: Define the fundamental types (double, int, ...) in
> namespace std.
>
> Solution 2: Define explicit functions ::swap(int,int), etc.

Solution 3:

namespace enhanced {
template <class Iter>
void rapidsort(Iter begin, Iter end)
{

using std::swap;
/*use swap(*begin,*end)*/
}
}

I hope I've learnt my lesson in this thread :-)

Thomas Maeder

unread,
Mar 25, 2000, 3:00:00 AM3/25/00
to
Andrei Alexandrescu wrote:
>
> What's worse about (2) is that, in particular for swap, reckless users
> will not be flagged by the compiler. If BigNum has value semantics (as
> it should), then std::swap will work on it, but very inefficiently.

So the BigNum designer should provide (or have provided) a better swap()
implementation.


> a) Savvy users will use the correct, verbose, ugly, deplorable,
> hateable idiom (2) and will get efficient programs.
>
> b) Plebeian users (as I have to humbly submit I am - I always thought
> you can and should overload std::algorithms for your types
> appropriately) will write code that uses std::swap explicitly, the
> compiler will not say a thing, and their programs will work, but
> slower.

I think this is a quality of implementation issue.


> I find this sad. I'm not a namespace expert, and now that I discovered
> some details I'd say, ignorance is bliss.

But I think that we both hope that the compiler writer is a namespace
expert.


> There's one more thing I don't like about this thread - the attitude
> that the Standard is perfect and that any criticism to it is an
> insult.

I haven't perceived it like this.

Andrei Alexandrescu

unread,
Mar 26, 2000, 3:00:00 AM3/26/00
to
Siemel B. Naran <sbn...@uiuc.edu> wrote in message
news:slrn8do62q....@localhost.localdomain...

> On 24 Mar 2000 18:04:48 -0500, Andrei Alexandrescu
<andre...@hotmail.com>
>
> >My question is: what's easier?
> >
> >1. Give someone a library and just ask them to call std algorithms with
the
> >objects of your types as they always did. That is, you define a class
BigNum
> >and they can call std::swap(a, b) for a and b being two BigNums. I find
this
> >a simple and intuitive rule.
>
> No, they should just call 'swap(a,b)'.

In essence, our dialog is like this. I say: "X is bad". You say: "Do X".

Let me explain my point again.

Let's say a library provides a type A in namespace N. Assume type A has
value semantics.

My idea is that it would be nice to let the user call std::swap(a1, a2) for
objects of type A. If the library provider felt it necessary to overload
std::swap, then the specialized version kicks in. Otherwise, the default
swap enters the stage.

What you sustain is just to use swap(a1, a2) in any context. In this case,
if I didn't say "using std::swap" or the shotgun "using namespace std" I
don't have a chance at getting to the default swap.

I don't like having to write one using declaration for nearly each of my
calls to standard library.

> They should call 'copy(...)' or 'sort(...)'.

Same comment here. I know what they should do according to the current
rule,. I'm just sustaining that the current rules are not that good.

> 1.
> Notice that declaring a function with the same name in different
namespaces
> is actually a form of overloading, thanks to Koenig lookup. Example:
> namespace A { class a { }; void action(a); }
> namespace B { class b { }; void action(b); }
> int main() { A::a a; B::b b; action(a); action(b); }

Koenig lookup is cool. What I don't like is the impenetrability of namespace
std.

> Try this analogy. Can we overload functions across the inheritance
> hierarchy? Yes, if the function is virtual.
> struct A { virtual void f(); }
> struct B : A { virtual void f(); }
> struct C : B { virtual void f(); }
> void silly(B& b) { b.f(); }
> The "b.f()" calls either B::f or C::f. But when we call explicitly
through
> the scope resolution operator, as in "b.A::f()" or "b.B::f()", we turn the
> virtual function mechanism off, thereby forcing a call to a specific f().
> Similarly, when we prepend the namespace 'std::', we force a call to a
> function in a specific namespace, thereby turning the namespace
overloading
> mechanism (ie, Koenig lookup) off.

Sorry, but your analogy doesn't appeal to me. For one thing, I don't have to
write "using A::f" before calling b.f().

> For this to work flawlessly, the builtin types should be in namespace std.
> int array[3]={1,3,2};
> sort(array,array+3); // error or ok?
> The call to sort(...) is an error in the current rules. But if "int *"

> were in namespace std, then the call is ok.

Even if the primitive types were considered in std, this will ***not*** work
flawlessly for a picosecond.

I repeat: if I define a type A in namespace N, I either want a specialized,
or the default, swap algorithm to enter in action ***without*** me having to
write using declarations all over the place.

Gee, this thread consumes me. :o)


Andrei

Andrei Alexandrescu

unread,
Mar 26, 2000, 3:00:00 AM3/26/00
to
Thomas Maeder <mae...@glue.ch> wrote in message
news:38DCE61C...@glue.ch...

> Andrei Alexandrescu wrote:
> >
> > What's worse about (2) is that, in particular for swap, reckless users
> > will not be flagged by the compiler. If BigNum has value semantics (as
> > it should), then std::swap will work on it, but very inefficiently.
>
> So the BigNum designer should provide (or have provided) a better swap()
> implementation.

I'm sorry, but you missed my point.

The library writer ***does*** provide a better swap algorithm. The problem
is that the user does not know, or is to lazy, to use the ^&%$%$(*&^(*&^#@
idiom:

{
using std::swap;
...
using std::kitchen_sink;

// now use swap(a, b) etc.
}

> I think this is a quality of implementation issue.

I hope by now you said "ah, I misunderstood".

> But I think that we both hope that the compiler writer is a namespace
> expert.

Ditto :o).

> > There's one more thing I don't like about this thread - the attitude
> > that the Standard is perfect and that any criticism to it is an
> > insult.

> I haven't perceived it like this.

Ditto :oD.

Gabriel Dos Reis

unread,
Mar 26, 2000, 3:00:00 AM3/26/00
to
"Andrei Alexandrescu" <andre...@hotmail.com> writes:

| Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
| news:flr9d0d...@poivre.cmla.ens-cachan.fr...
| > Consider:
| > 1) template<typename T> void swap(T&, T&);
| > 2) template<typename T> void swpa(MyType<T>&, MyType<T>&)
| >
| > In the first template, replace T with unique_type (where unique_type
| > is a unique type). Now attempt template argument deduction for the
| > second template against the parameter list (unique_type&, unique_type&).
| > That argument deduction fails. So the first template is *not* at
| > least as specialized as the second.
| >
| > Repeat the same process in the reverse way. Here argument deduction
| > for the first template against (MyType<unique_type>&,
| MyType<unique_type>&)
| > succeeds. So the second template is at least as specialized as the
| > first. It follows from 14.5.5.2/5 that the second template is more
| > specialized than the first. So swap<int>(MyType<int>&, MyType<int>&)
| > is selected.
|
| Basically you prove here that overloading std:: algorithms for user-defined
| types is not dangerous and does not engender any problem at all.

The only thing I tried to explain is partial ordering.

I didn't attempt anything to prove something else.

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gabriel Dos Reis

unread,
Mar 26, 2000, 3:00:00 AM3/26/00
to
"Andrei Alexandrescu" <andre...@hotmail.com> writes:

| Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message

| news:flzorod...@poivre.cmla.ens-cachan.fr...
| > I think the rationale is that any name found by lookup in std:: is
| > guaranteed to be defined either by the standard or the implementation
| > (this expresses the reserved nature of std).
|
| What about partial/total specialization of classes in std:: for user-defined
| types, then? Is that an "exception to the reserved nature of std"?

I don't think they are exceptions. Specializations are found by
lookup.

Gabriel Dos Reis

unread,
Mar 26, 2000, 3:00:00 AM3/26/00
to
"Andrei Alexandrescu" <andre...@hotmail.com> writes:

| Siemel B. Naran <sbn...@uiuc.edu> wrote in message

| news:slrn8dkbp5....@localhost.localdomain...
|
| [snip all]
|
| You are 96% happy, but I'm still not satisfied.
|

| My question is: what's easier?
|
| 1. Give someone a library and just ask them to call std algorithms with the
| objects of your types as they always did. That is, you define a class BigNum
| and they can call std::swap(a, b) for a and b being two BigNums. I find this
| a simple and intuitive rule.

What is intuitive is in the eye of the beholder.

| 2. Give someone a library and tell them they must use the following idiom:
|
| {
| BigNum a;
| using std::some_algorithm;
| some_algorithm(a);
| }
|
| in *every* darn place they ever use a standard algorithm on any of your
| types.

BigNum author is supposed to have documented his library. In which
case it is known whether or not some_algorithm is part of his library
or not. If it is part of the library, then there is no need for the
using-declaration. If not the just saying std::some_algotrithm(a) is
plain sufficient.

[...]

| b) Plebeian users (as I have to humbly submit I am - I always thought you
| can and should overload std::algorithms for your types appropriately) will
| write code that uses std::swap explicitly, the compiler will not say a
| thing, and their programs will work, but slower.

You can overload std::algorithms. In your own namespaces. The rest
is a matter of education.


[...]

| There's one more thing I don't like about this thread - the attitude that

| the Standard is perfect and that any criticism to it is an insult.

Could you quote any message to that effect?

What I have seen so far is:
o confusion of concepts -- clarifications have been given.
o unfounded claim -- they have been disposed of.
o extension proposition.

Peter Dimov

unread,
Mar 26, 2000, 3:00:00 AM3/26/00
to
Andrei Alexandrescu <andre...@hotmail.com> wrote in message
news:sdojfod...@news.supernews.com...

> Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
> news:flvh2cd...@poivre.cmla.ens-cachan.fr...
> > I do understand the desire to overload function template in std.
> > But I think the main issue is user education. I think they got there
> > because of a particular design of their program. The first thing we
> > need to address is whether that design can be corrected.
>
> Sure. "Hey, users, don't do what's intuitive and terse. Instead, litter
your
> code with 'using std::whatever' and then call unqualified whatever()
> whenever you need. Otherwise, your design is broken. By definition."

I'd like to add that using unqualified functions in user code may decrease
the need for specializing (overloading) std:: functions, but another problem
still remains.

Does the Standard guarantee that a standard algorithm that needs to swap
things will find my swap() function using Koenig lookup? I don't think so.
The implementation of std::sort is free to use ::std::swap(a, b), if I'm not
mistaken.

There _must_ be a way to provide a more efficient implementation for

std::swap(UDT<T>&, UDT<T>&).

Defining a standard interface for swapping things and then requiring users
to _not_ use it is very counter-intuitive.

--
Peter Dimov
Multi Media Ltd.

Gabriel Dos Reis

unread,
Mar 26, 2000, 3:00:00 AM3/26/00
to
"Andrei Alexandrescu" <andre...@hotmail.com> writes:

| Siemel B. Naran <sbn...@uiuc.edu> wrote in message

| news:slrn8do62q....@localhost.localdomain...
| > On 24 Mar 2000 18:04:48 -0500, Andrei Alexandrescu
| <andre...@hotmail.com>
| >

| > >My question is: what's easier?
| > >
| > >1. Give someone a library and just ask them to call std algorithms with
| the
| > >objects of your types as they always did. That is, you define a class
| BigNum
| > >and they can call std::swap(a, b) for a and b being two BigNums. I find
| this
| > >a simple and intuitive rule.
| >

| > No, they should just call 'swap(a,b)'.
|
| In essence, our dialog is like this. I say: "X is bad". You say: "Do X".

That is not my experience. Right now I'm seeing:
- X is bad.
- Do Y.

| Let me explain my point again.
|
| Let's say a library provides a type A in namespace N. Assume type A has
| value semantics.
|
| My idea is that it would be nice to let the user call std::swap(a1, a2) for
| objects of type A.

If the standard swap is appropriate.


| ... If the library provider felt it necessary to overload


| std::swap, then the specialized version kicks in. Otherwise, the default
| swap enters the stage.

If the library provider felt it necessary to overload std::swap then
surely he would have said so in the documentation. In which case
saying just 'swap' should be sufficient -- or some_author::swap which
I find informative.

I can understand that reading the documentation can be painful, but
what semantics do you expect from a construct about which you don't
care to learn?

| What you sustain is just to use swap(a1, a2) in any context. In this case,
| if I didn't say "using std::swap" or the shotgun "using namespace std" I
| don't have a chance at getting to the default swap.

Programs should behave consistently with their syntactic expression.
I know we (you Andrei and me) don't perceive namespaces (especially
namespace std), and name lookup from the same point of view. If I say
'std::some_algorithm', then I'm expecting some_algorithm (found by
lookup in namespace std) to be that some_algorithm defined by the
standard or by the particular implementation I'm using. If I say
unqualified 'some_algorithm' I'm expecting to get that some_algorithm
that happens to fit my data.

If the author of the library didn't expect std::some_algorithm to be
used with his some_author::nifty_data_type then the unqualified
some_algorithm() will give me a chance to catch that error at
compile-time. If he did,-- because he was careful (or competent?) --
he would have inserted the appropriate using-declarations in namespace
some_author so that Koenig lookup can find it.

| I don't like having to write one using declaration for nearly each of my
| calls to standard library.

You don't have to.

[...]

| Koenig lookup is cool. What I don't like is the impenetrability of namespace
| std.

As the name space of identifiers beginning with '__' ?

[...]

| Sorry, but your analogy doesn't appeal to me. For one thing, I don't have to
| write "using A::f" before calling b.f().

No one is asking you to write such thing every time you need to use a
standard algorithm. I find your claim to be an overstatement of the
case.

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Andrei Alexandrescu

unread,
Mar 27, 2000, 3:00:00 AM3/27/00
to
Peter Dimov <pdi...@mmltd.net> wrote in message
news:8bl5md$6h8$1...@weber.techno-link.com...
[snip]

> There _must_ be a way to provide a more efficient implementation for
>
> std::swap(UDT<T>&, UDT<T>&).
>
> Defining a standard interface for swapping things and then requiring users
> to _not_ use it is very counter-intuitive.

I agree with the points you made in your post. But, you see, what's
intuitive depends on who looks at it. We just have been proven thoroughly
that we are utterly mistaken and that the standard is perfect.


Andrei

P.S. Don't forget to write a using-declaration before calling into *any* STL
algorithm on user-defined types, and not to use "std::". This is intuitive
:o).

Andrei Alexandrescu

unread,
Mar 27, 2000, 3:00:00 AM3/27/00
to
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
news:fl66u9q...@poivre.cmla.ens-cachan.fr...

I was willing to drop all this, but I just got a silver opportunity to make
some points :o). I have to admit I'm frustrated by this thread, and amazed
on such unreasonable things are considered reasonable.

[snip]


> If the library provider felt it necessary to overload std::swap then
> surely he would have said so in the documentation. In which case
> saying just 'swap' should be sufficient -- or some_author::swap which
> I find informative.

The problem has to do with uniform call syntax and versioning. "Hey, we just
updated our BigNum library. If you used std::swap on BigNums, which worked
in the past, that will still work - you see, BigNum still has value
semantics - but what you should do is to make a search-and-replace.
Otherwise, poor soul, you won't even get a compile-time error; only your
programs will run like molasses".

I find this unacceptable and it takes me a lot of energy to understand how
you anybody else thinks it's acceptable.

std::swap is an algorithm that does a well-known action, in a well-known
manner. It works on *all* types with value semantics. It works
*inefficiently* and *un-exception-safe* for most user-defined types.
Therefore, people who define new types that would lead to an incorrect
std::swap instantiation ought to prevent that by overloading std::swap. At
least that's my view.

> I can understand that reading the documentation can be painful, but
> what semantics do you expect from a construct about which you don't
> care to learn?

Thanks. I think this point is made moot by the point with versioning above.

> Programs should behave consistently with their syntactic expression.
> I know we (you Andrei and me) don't perceive namespaces (especially
> namespace std), and name lookup from the same point of view. If I say
> 'std::some_algorithm', then I'm expecting some_algorithm (found by
> lookup in namespace std) to be that some_algorithm defined by the
> standard or by the particular implementation I'm using.

Cool. Here comes the canon counter-argument.

If you say std::some_container<MyType>, don't you expect some_container
(found by lookup in namespace std) to be that some_container defined by the
standard or by the particular implementation you're using?

However, this is *not* what happens.

I think you will admit now that this fact shatters your whole argument quite
strongly.

> If the author of the library didn't expect std::some_algorithm to be
> used with his some_author::nifty_data_type then the unqualified
> some_algorithm() will give me a chance to catch that error at
> compile-time. If he did,-- because he was careful (or competent?) --
> he would have inserted the appropriate using-declarations in namespace
> some_author so that Koenig lookup can find it.

I don't think I have to add much more to the points above, but here goes.
The library authors did expect BigNum to work with std::swap so they didn't
think of providing a specialized version. The new version of the library
uses dynamic allocation and needs a different swap. Otherwise, out the
window is exception safety. There is no chance to render previous calls to
std::swap on BigNums compile-time errors.

This is bad.

> | I don't like having to write one using declaration for nearly each of my
> | calls to standard library.
>
> You don't have to.

I have to, if I want to give a crack to specialization, or, if a
specialization does not exist, to rely on the default algorithm. *This* is
what I want, and I think it's legitimate to want that. In this thread, I
don't need solutions to any other problem than this one.

> | Koenig lookup is cool. What I don't like is the impenetrability of
namespace
> | std.
>
> As the name space of identifiers beginning with '__' ?

This is something totally different. I don't need to do anything with __
identifiers. I don't want to specialize or overload __ identifiers. I don't
see how all this has anything at all to do with our discussion.

> | Sorry, but your analogy doesn't appeal to me. For one thing, I don't
have to
> | write "using A::f" before calling b.f().
>
> No one is asking you to write such thing every time you need to use a
> standard algorithm. I find your claim to be an overstatement of the
> case.

See above. I find my claim perfectly reasonable, and I actually think it's a
pretty obvious, easy to win, cause. I can't even understand why I have to
spend so much time explaining the obvious. You couldn't line up any
arguments that I'd find reasonable, yet you are very convinced you are
right, just as I am. Yet I utterly fail to get to the gist of your
certainity that what's now in the Standard is okay. Actually, the only
compelling argument is that this is how the Standard is, and we have to live
with it. But it's definitely not cool :o}.


Andrei

Andrei Alexandrescu

unread,
Mar 27, 2000, 3:00:00 AM3/27/00
to
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
news:flr9cyo...@poivre.cmla.ens-cachan.fr...

> "Andrei Alexandrescu" <andre...@hotmail.com> writes:
> | There's one more thing I don't like about this thread - the attitude
that
> | the Standard is perfect and that any criticism to it is an insult.
>
> Could you quote any message to that effect?
>
> What I have seen so far is:
> o confusion of concepts -- clarifications have been given.
> o unfounded claim -- they have been disposed of.
> o extension proposition.

Ah, what I've seen so far is:

* confusion of concepts - thanks for the clarifications.

* reasonable claims - they have been "disposed of" without any arguments
that the current scheme has any advantage or usefulness. (I refer to the
"current scheme" as of the interdiction to overload algorithms in namespace
std.)

* a proposition to repair something that's utterly broken, fundamentally
flawed, and a potential source of subtle errors in code that looks
innocuous, compiles fine, and even runs sometimes (see the exception safety
issue in another post of mine). The proposition was dismissed by yourself
for being not that smart, and - worse - ignored by all other participants to
this newsgroup, who have an influence in changing things.

Mark Rodgers

unread,
Mar 27, 2000, 3:00:00 AM3/27/00
to
Andrei Alexandrescu <andre...@hotmail.com> wrote in message

> The problem has to do with uniform call syntax and versioning. "Hey, we


> just updated our BigNum library. If you used std::swap on BigNums, which
> worked in the past, that will still work - you see, BigNum still has value
> semantics - but what you should do is to make a search-and-replace.
> Otherwise, poor soul, you won't even get a compile-time error; only your
> programs will run like molasses".

I think their point was that you shouldn't have used std::swap, you should
just have used plain swap in the first place. I think the onus was on the
BigNum implementer to do either

namespace N
{
class BigNum {...};
void swap(BigNum &x, BigNum &y) { ... }
}

or

namespace N
{
class BigNum {...};
using std::swap;
}

The latter could be changed to the former without breaking anyone's code
as long as they always wrote

N::BigNum a, b;
swap(a, b);

and didn't "erroneously" write

N::BigNum a, b;
std::swap(a, b);

> I find this unacceptable and it takes me a lot of energy to understand how
> you anybody else thinks it's acceptable.

I also think it is unacceptable.

1. It effectively reserves names in all namespaces. It seems that
namespaces become useless.
2. It is unwieldy. It seems that when I write by new class, I have
to list every single algorithm in every namespace I know about,
so that my clients can call them without prefixing them with
the namespace name.
3. It doesn't work with classes in the std library. For example,
suppose I create a super duper new algorithm

namespace N

template <typename T> void super_duper(T &x)
{ ... }
}

How can clients call this with standard containers? It seems that
I need to add

namespace std {
using N::super_duper;
}

but of course I can't. And if I know I can do my super duper
algorithm more efficiently with vectors, it seems I need to
write

namespace std {
template <typename T>
void super_duper(vector<T> &v)
{ ... }
}

Nope. Can't do that either.

Alternatively we could say that std::swap is how you spell "swap
two elements" and that N::swap is free to mean something else. We
could say that if we want to swap objects of classes we have
written, then we are free to specialise std::swap. Then all we need
to fix is the problem that we cannot legally provide a "specialised"
std::swap for class templates. For the life of me I cannot see how
this change could break anything.

Mark

Ross Smith

unread,
Mar 27, 2000, 3:00:00 AM3/27/00
to
"Gabriel Dos Reis" <dos...@cmla.ens-cachan.fr> wrote in message
news:flr9cyo...@poivre.cmla.ens-cachan.fr...
> "Andrei Alexandrescu" <andre...@hotmail.com> writes:
>
> | 2. Give someone a library and tell them they must use the following
idiom:
> |
> | {
> | BigNum a;
> | using std::some_algorithm;
> | some_algorithm(a);
> | }
> |
> | in *every* darn place they ever use a standard algorithm on any of
your
> | types.
>
> BigNum author is supposed to have documented his library. In which
> case it is known whether or not some_algorithm is part of his library
> or not. If it is part of the library, then there is no need for the
> using-declaration. If not the just saying std::some_algotrithm(a) is
> plain sufficient.

But the point you keep evading is that this approach *doesn't work for
arbitrary types*. You have to know in advance that the algorithm is
either in a specific namespace or always in the same namespace as the
type.

Consider this:

template <typename T> void correct_order(T& t1, T& t2) {
if (t2 < t1)
swap(t1, t2);
}

As written, it won't work if T is a primitive arithmetic type. If swap()
is replaced with std::swap(), it won't work with a user-defined type
whose swap() function is in a namespace other than std. If the UDT is a
template, its swap() can't be put in namespace std because of the ban on
partial specialisation.

Please explain how to solve this problem. Apparently the rest of us are
too dumb to figure it out.

--
Ross Smith <ros...@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"So that's 2 T-1s and a newsfeed ... would you like clues with that?"
-- Peter Da Silva

Dave Abrahams

unread,
Mar 27, 2000, 3:00:00 AM3/27/00
to
in article fl66u9q...@poivre.cmla.ens-cachan.fr, Gabriel Dos Reis at
dos...@cmla.ens-cachan.fr wrote on 3/26/00 11:12 PM:

> Programs should behave consistently with their syntactic expression.
> I know we (you Andrei and me) don't perceive namespaces (especially
> namespace std), and name lookup from the same point of view. If I say
> 'std::some_algorithm', then I'm expecting some_algorithm (found by
> lookup in namespace std) to be that some_algorithm defined by the
> standard or by the particular implementation I'm using.

Then your expectations might be violated, since the user is allowed to fully
specialize std::swap<UDT>.

This world is much too complicated, IMO.

> If I say
> unqualified 'some_algorithm' I'm expecting to get that some_algorithm
> that happens to fit my data.

Then your expectation might be violated, if your data happens to be made up
of builtin types. Don't forget, even types in namespaces might be typedefs
for builtin types.

> If the author of the library didn't expect std::some_algorithm to be
> used with his some_author::nifty_data_type then the unqualified
> some_algorithm() will give me a chance to catch that error at
> compile-time. If he did,-- because he was careful (or competent?) --
> he would have inserted the appropriate using-declarations in namespace
> some_author so that Koenig lookup can find it.

Whew! What happens in this case?

namespace some_author {
struct nifty_data_type {...}; // swapped fine by std::swap
using std::swap; // for use on nifty_data_type

.... // much later...

template <class T>
struct nifty_data_type2 {...}; // needs special swap
template <class T>
void swap(nifty_data_type2<T>&, nifty_data_type2<T>&);
} // namespace some_author


-Dave

nik...@my-deja.com

unread,
Mar 27, 2000, 3:00:00 AM3/27/00
to
In article <flr9d0d...@poivre.cmla.ens-cachan.fr>,
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote:

[...]

> No. That is not what 14.5.5.2/[2-3] say.

> Consider:
> 1) template<typename T> void swap(T&, T&);
> 2) template<typename T> void swpa(MyType<T>&, MyType<T>&)
>
> In the first template, replace T with unique_type (where unique_type
> is a unique type). Now attempt template argument deduction for the
> second template against the parameter list (unique_type&,
unique_type&).
> That argument deduction fails. So the first template is *not* at
> least as specialized as the second.
>
> Repeat the same process in the reverse way. Here argument deduction
> for the first template against (MyType<unique_type>&,
MyType<unique_type>&)
> succeeds. So the second template is at least as specialized as the
> first. It follows from 14.5.5.2/5 that the second template is more
> specialized than the first. So swap<int>(MyType<int>&, MyType<int>&)
> is selected.

Ah, light dawns! Thanks for explaining this.


Sent via Deja.com http://www.deja.com/
Before you buy.

Rob Stewart

unread,
Mar 27, 2000, 3:00:00 AM3/27/00
to
Andrei Alexandrescu wrote:
>
> Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
> news:fl66u9q...@poivre.cmla.ens-cachan.fr...
>
> I was willing to drop all this, but I just got a silver opportunity to make
> some points :o). I have to admit I'm frustrated by this thread, and amazed
> on such unreasonable things are considered reasonable.

I'm not sure I fully understand what Gabriel (and Siemel) is
trying to say, but I think I can clarify a couple of points for
you. (BTW, I understand your confusion. I thought the same
things as you -- and still think mostly the same. I'm looking
forward to understanding this stuff more fully.)

> > If the library provider felt it necessary to overload std::swap then
> > surely he would have said so in the documentation. In which case
> > saying just 'swap' should be sufficient -- or some_author::swap which
> > I find informative.
>

> The problem has to do with uniform call syntax and versioning. "Hey, we just
> updated our BigNum library. If you used std::swap on BigNums, which worked
> in the past, that will still work - you see, BigNum still has value
> semantics - but what you should do is to make a search-and-replace.
> Otherwise, poor soul, you won't even get a compile-time error; only your
> programs will run like molasses".
>

> I find this unacceptable and it takes me a lot of energy to understand how
> you anybody else thinks it's acceptable.

I think that here, Gabriel is saying that the user should have
already been calling "swap" not "std::swap" so there's no
syntactical change.

> std::swap is an algorithm that does a well-known action, in a well-known
> manner. It works on *all* types with value semantics. It works
> *inefficiently* and *un-exception-safe* for most user-defined types.
> Therefore, people who define new types that would lead to an incorrect
> std::swap instantiation ought to prevent that by overloading std::swap. At
> least that's my view.

Because you want to avoid a using declaration (or directive)
anywhere you want to use std::swap() or some type specific
swap(), you assume overloading. That is not permitted, and
apparently the crux of the issue.

> > Programs should behave consistently with their syntactic expression.
> > I know we (you Andrei and me) don't perceive namespaces (especially
> > namespace std), and name lookup from the same point of view. If I say
> > 'std::some_algorithm', then I'm expecting some_algorithm (found by
> > lookup in namespace std) to be that some_algorithm defined by the
> > standard or by the particular implementation I'm using.
>

> Cool. Here comes the canon counter-argument.

I know you're frustrated; try to control the editorializing.

> If you say std::some_container<MyType>, don't you expect some_container

> (found by lookup in namespace std) to be that some_container defined by the
> standard or by the particular implementation you're using?

Yes, and that's what he was implying by his previous paragraph.

> However, this is *not* what happens.

If you write "std::swap" that *is* what happens. If you write
"swap" it may not invoke std::swap(). In a complex class
hierarchy, if you call fubar(), a mf of a base class, the
compiler invokes that for you. If you provide your own, you
either hide or override the base class function (depending upon
whether it is virtual). In any case, calling fubar() from the
derived class' mfs always invokes the derived class' fubar(). If
you want to ensure that the base class fubar() is invoked, you
must use scope resolution.

Therefore, if you always invoke fubar() using scope resolution,
then you always get the base class' fubar(). If you don't scope
resolve the call, then you get a different fubar() depending upon
the type of the pointer, reference, or instance you invoke it
with (and whether it is virtual).

IOW, when you use scope resolution (std::swap() in the
discussion), you always get that one. When you don't use scope
resolution, the compiler selects the best fit. This, of course,
means that in the scope (possibly namespace scope -- Gabriel's
point) you must include a using declaration for std::swap() so
calling swap() *can* invoke std::swap() if appropriate.

> I think you will admit now that this fact shatters your whole argument quite
> strongly.

I don't think so. If you still do, you need to explain further.

> > If the author of the library didn't expect std::some_algorithm to be
> > used with his some_author::nifty_data_type then the unqualified
> > some_algorithm() will give me a chance to catch that error at
> > compile-time. If he did,-- because he was careful (or competent?) --
> > he would have inserted the appropriate using-declarations in namespace
> > some_author so that Koenig lookup can find it.
>

> I don't think I have to add much more to the points above, but here goes.
> The library authors did expect BigNum to work with std::swap so they didn't
> think of providing a specialized version. The new version of the library
> uses dynamic allocation and needs a different swap. Otherwise, out the
> window is exception safety. There is no chance to render previous calls to
> std::swap on BigNums compile-time errors.
>
> This is bad.

Here is where I think Gabriel means a careful, competent,
knowledgeable library implementor would have included a using
declaration for std::swap() and the other algorithms s/he wanted
to allow. IOW, the implementor must explicitly allow the
compiler to invoke the standard algorithms. I think Gabriel's
saying that this is, or should be, standard operating procedure
for implementors.

Whether this is a good thing to require is another matter
entirely.

> > | I don't like having to write one using declaration for nearly each of my
> > | calls to standard library.
> >
> > You don't have to.

Gabriel, if I've missed your intent, please explain yourself
here. Otherwise, this will become a "Yes, I do," "No, you
don't," kind of argument.

> I have to, if I want to give a crack to specialization, or, if a
> specialization does not exist, to rely on the default algorithm. *This* is
> what I want, and I think it's legitimate to want that. In this thread, I
> don't need solutions to any other problem than this one.

Given implementor prescience, you can get this, but only if you
don't use scope resolution. As other's have said, however, this
means that the algorithms' names *must* be treated as sacred in
all namespaces. That is, *any* non-member function called the
same as a standard algorithm *must* provide compatible semantics
with the standard algorithm. This places a serious burden on the
selection of standard algorithm names and on the names selected
for non-standard semantics operations that would otherwise be
named the same.

> > | Sorry, but your analogy doesn't appeal to me. For one thing, I don't
> have to
> > | write "using A::f" before calling b.f().
> >
> > No one is asking you to write such thing every time you need to use a
> > standard algorithm. I find your claim to be an overstatement of the
> > case.
>
> See above. I find my claim perfectly reasonable, and I actually think it's a
> pretty obvious, easy to win, cause. I can't even understand why I have to
> spend so much time explaining the obvious. You couldn't line up any
> arguments that I'd find reasonable, yet you are very convinced you are
> right, just as I am. Yet I utterly fail to get to the gist of your
> certainity that what's now in the Standard is okay. Actually, the only
> compelling argument is that this is how the Standard is, and we have to live
> with it. But it's definitely not cool :o}.

You both fail to fully comprehend the other's knowledge and
perspective. I hope I've shed some light on matters to help you
understand one another so we can finish exploring the technical
details.

--
Robert Stewart | rob-at-giage-dot-com
Software Engineer | using std::disclaimer;
Giage, Ltd. | http://www.giage.com

Peter Dimov

unread,
Mar 27, 2000, 3:00:00 AM3/27/00
to
Andrei Alexandrescu <andre...@hotmail.com> wrote in message
news:sdtt87...@news.supernews.com...

> Peter Dimov <pdi...@mmltd.net> wrote in message
> news:8bl5md$6h8$1...@weber.techno-link.com...
> [snip]
> > There _must_ be a way to provide a more efficient implementation for
> >
> > std::swap(UDT<T>&, UDT<T>&).
> >
> > Defining a standard interface for swapping things and then requiring
users
> > to _not_ use it is very counter-intuitive.
>
> I agree with the points you made in your post. But, you see, what's
> intuitive depends on who looks at it.

Quite possibly. I used 'very counter-intuitive' to put it mildly, so to
speak.

> We just have been proven thoroughly
> that we are utterly mistaken and that the standard is perfect.

I don't think so (sarcasm notwithstanding.)

The point I raised still holds: are standard algorithms supposed to find and
call user defined functions that happen to have the same name as other
standard functions?

Example:

#include <stdio.h>
#include <queue>
#include <vector>

namespace N
{
struct less
{
operator() (int a, int b)
{
return a < b;
}
};

void push_heap(int*, int*, less)
{
puts("push_heap");
}
}

int main()
{
std::priority_queue<int, std::vector<int>, N::less> pq;


pq.push(5);
pq.push(1);
pq.push(2);

return 0;
}

What is the behavior of this program? Should it depend on the
implementation, according to the Standard? Because, in real life, it does.

Undefined behavior, perhaps? I don't see any.

--
Peter Dimov
Multi Media Ltd.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Thomas Maeder

unread,
Mar 28, 2000, 3:00:00 AM3/28/00
to
Andrei Alexandrescu wrote:
>
> I'm sorry, but you missed my point.

No.


> The library writer ***does*** provide a better swap algorithm. The
> problem is that the user does not know, or is to lazy, to use the
> ^&%$%$(*&^(*&^#@ idiom:
>
> {

> using std::swap;
> ...


> using std::kitchen_sink;
>
> // now use swap(a, b) etc.
> }

Before I learnt otherwise in this thread, I thought that it wasn't possible
to provide specialized implementations of std algorithms. I would have
agreed that this was a defect in the language.

But it isn't, as Gabriel has shown me. What you'd like to add to the
language is not a necessity, but nice to have IMHO. I am not against your
suggestions, but I don't think that it *has* to fixed as a defect.


> > I think this is a quality of implementation issue.
>
> I hope by now you said "ah, I misunderstood".

No. I now say that good compilers should produce warnings when the above
idiom is not used.

Andrei Alexandrescu

unread,
Mar 28, 2000, 3:00:00 AM3/28/00
to
Rob Stewart <donot...@giage.com> wrote in message
news:38DF983A...@giage.com...

Sorry Rob, again I was willing to drop this, but I just got yet another
silver opportunity to make a point :o).

> I think that here, Gabriel is saying that the user should have
> already been calling "swap" not "std::swap" so there's no
> syntactical change.

Fact 1: non admitting overloading in std requires user saviour. No user
saviour does not lead to non-compiling programs. Instead, it leads to
programs that run, but are potentially incorrect and suboptimal.

> > Cool. Here comes the canon counter-argument.
>
> I know you're frustrated; try to control the editorializing.

I don't think what I said is offensive. This is how I've seen my
counter-argument (which btw you misunderstood - see below): a canon that
blows away the argument in favor of the current rule.

> > If you say std::some_container<MyType>, don't you expect some_container
> > (found by lookup in namespace std) to be that some_container defined by
the
> > standard or by the particular implementation you're using?
>
> Yes, and that's what he was implying by his previous paragraph.
>
> > However, this is *not* what happens.
>
> If you write "std::swap" that *is* what happens.

Here's the misunderstanding. I was talking about containers. Read the quote
from my post again: I was talking about "std::some_container". Not
some_algorithm. If I write std::vector<MyType>, I can get to a
specialization written by the implementor of MyType.

Fact 2: I can enter namespace std in two ways:

a) I can specialize containers
b) I can specialize algorithms (oops)

However, I cannot overload algorithms, which means that I cannot implement
efficient algorithms for template types.

> IOW, when you use scope resolution (std::swap() in the
> discussion), you always get that one.

Wrong. I can specialize std::swap for any type of mine - it just doesn't
have to be template:

// 100% kosher
class MyClass { ... };

namespace std
{
template<> void swap(MyClass& lhs, MyClass& rhs)
{
...
}
}

It is obvious to me that leaving template types aside was an oversight.

> > I think you will admit now that this fact shatters your whole argument
quite
> > strongly.
>
> I don't think so. If you still do, you need to explain further.

I think I just did.

> Here is where I think Gabriel means a careful, competent,
> knowledgeable library implementor would have included a using
> declaration for std::swap() and the other algorithms s/he wanted
> to allow. IOW, the implementor must explicitly allow the
> compiler to invoke the standard algorithms. I think Gabriel's
> saying that this is, or should be, standard operating procedure
> for implementors.

I find this unreasonable.

> Whether this is a good thing to require is another matter
> entirely.

I think I understood the current rules. I was discussion exactly why I see
things as being good.

> As other's have said, however, this
> means that the algorithms' names *must* be treated as sacred in
> all namespaces.

They're not sacred (17.4.3.1/1). Let's make this crystal clear: you can
specialize *any* std algorithm for your types.

The problem is, you cannot overload it for template types and take advantage
of partial ordering.

What reasonable explanation can be found to:

Fact 3: User-defined types can hook std algorithms, but user-defined
templates are left to Koenig lookup.

> You both fail to fully comprehend the other's knowledge and
> perspective. I hope I've shed some light on matters to help you
> understand one another so we can finish exploring the technical
> details.

I don't think I fail. So far I did my best to understand all the posts of
this thread, and in the end I think I got a correct understanding on what's
going on. On the contrary, my own posts have been thoroughly misunderstood,
misinterpreted, or misread.


Andrei

alan_gr...@my-deja.com

unread,
Mar 28, 2000, 3:00:00 AM3/28/00
to
> I suggest adding:
>
> A program may add to namespace std function template declarations
> which overload any standard library function template name. Such
> declarations result in undefined behavior unless the declaration
> depends on a user-defined name of external linkage and unless the
> function template meets the standard library requirements for
> the original template.

Not bad for a first attempt, but this has the potential to break
existing code. (I can't remember who posted the following example to
the boost mailing list.)


// In some header (and allowed under these rules)...
namespace my_ms { template<typename T> struct foo {}; }


namespace std {
template<typename T>

my_ns::foo<T>& use_facet(const locale&) { ... }
}


// In some user code (and conforming under current rules)...
void bar()
{
std::use_facet<int>(std::locale()); // now ambiguous
}

What is needed is a form of words that doesn't allow this (and
potentially other) "silly in practice - but legally important"
examples<g>.
--
Alan Griffiths (alan.gr...@experian.com, +44 115 934 4517)
Senior Systems Consultant, Experian


Sent via Deja.com http://www.deja.com/
Before you buy.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

John Maddock

unread,
Mar 28, 2000, 3:00:00 AM3/28/00
to
>
> template <typename T> void correct_order(T& t1, T& t2) {
> if (t2 < t1)
> swap(t1, t2);
> }
>
>As written, it won't work if T is a primitive arithmetic type. If swap()
>is replaced with std::swap(), it won't work with a user-defined type
>whose swap() function is in a namespace other than std. If the UDT is a
>template, its swap() can't be put in namespace std because of the ban on
>partial specialisation.

true, but see below:

>Please explain how to solve this problem. Apparently the rest of us are
>too dumb to figure it out.

template <typename T> void correct_order(T& t1, T& t2) {
using std::swap;


if (t2 < t1)
swap(t1, t2);
}

Will do what you want - that is default to std::swap unless there is a
better version available in the same namespace as T (or a friend of
T).

John Maddock
http://ourworld.compuserve.com/homepages/John_Maddock/

Peter Dimov

unread,
Mar 28, 2000, 3:00:00 AM3/28/00
to
Andrei Alexandrescu <andre...@hotmail.com> wrote in message
news:se01lfa...@news.supernews.com...

> Fact 3: User-defined types can hook std algorithms, but user-defined
> templates are left to Koenig lookup.

That's the gist of the matter. std::swap<UDT> is permitted, std::swap<UDT<T>
> is not, creating a completely artificial 'disbalance' between user
templates and 'normal' user defined types.

Let me expand on this further:

Fact 4: There is no way to supply an efficient swap() to std::sort or
std::reverse. Not only because of Fact 3, but because std::sort and
std::reverse are not required to use swap(), fully qualified or not.

In fact, in all the implementations I checked, they don't.

BTW, #4 is more important to me than #3.

Fact 5: All this heated debate can be dealt with in one swift stroke. Simply
allow partial specialization of function templates. The arguments against
this so far boil down to

5.1. This is equivalent to overloading. (It is not. And not only in
namespace std.)
5.2. It will needlessly complicate the lookup rules even further. (It will
not. Specializations do not affect lookup rules. They do affect which
function is called, but this feature has zero cost, i.e. if you don't
partially specialize, you'll not be bitten by it. Not so with Koenig
lookup.)

--
Peter Dimov
Multi Media Ltd.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Ross Smith

unread,
Mar 28, 2000, 3:00:00 AM3/28/00
to
"John Maddock" <John_M...@compuserve.com> wrote in message
news:38e08b61...@news.freeserve.net...

> >
> > template <typename T> void correct_order(T& t1, T& t2) {
> > if (t2 < t1)
> > swap(t1, t2);
> > }
> >
> >As written, it won't work if T is a primitive arithmetic type. If
swap()
> >is replaced with std::swap(), it won't work with a user-defined type
> >whose swap() function is in a namespace other than std. If the UDT is
a
> >template, its swap() can't be put in namespace std because of the ban
on
> >partial specialisation.
>
> true, but see below:
>
> >Please explain how to solve this problem. Apparently the rest of us
are
> >too dumb to figure it out.
>
> template <typename T> void correct_order(T& t1, T& t2) {
> using std::swap;
> if (t2 < t1)
> swap(t1, t2);
> }
>
> Will do what you want - that is default to std::swap unless there is a
> better version available in the same namespace as T (or a friend of
> T).

All right, that will work (although I don't understand what you meant by
that last bit -- what do friends have to do with it?). But I still say
it's an ugly and potentially dangerous hack to get around the ban on
partial specialisation of standard algorithms (or partial overloading or
whatever the heck it's officially called).

Have we ever had a definitive answer from somebody on the committee as
to whether they intentionally disallowed it (if so, why?), or was it
just an oversight (like the contiguous vector issue)? If the latter, it
may not be too late to fix it with a DR.

--
Ross Smith <ros...@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"So that's 2 T-1s and a newsfeed ... would you like clues with that?"
-- Peter Da Silva

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gabriel Dos Reis

unread,
Mar 28, 2000, 3:00:00 AM3/28/00
to
"Peter Dimov" <pdi...@mmltd.net> writes:

| Andrei Alexandrescu <andre...@hotmail.com> wrote in message
| news:se01lfa...@news.supernews.com...
|
| > Fact 3: User-defined types can hook std algorithms, but user-defined
| > templates are left to Koenig lookup.
|
| That's the gist of the matter. std::swap<UDT> is permitted,
std::swap<UDT<T>
| > is not, creating a completely artificial 'disbalance' between user
| templates and 'normal' user defined types.

I think there is already a language distinction between
swap<>(UDT&, UDT&) and swap(UDT<T>&, UDT<T>&).
The former is an explicit specialization and the latter is an
overloading. I noticed you said std::swap<UDT<T> >. It isn't
clear what you meant exactly. In case you meant "a partial
specialization" that requires yet a another core language change.

| Let me expand on this further:
|
| Fact 4: There is no way to supply an efficient swap() to std::sort or
| std::reverse. Not only because of Fact 3, but because std::sort and
| std::reverse are not required to use swap(), fully qualified or not.

Yes, there a lack of interface documentation here.


| In fact, in all the implementations I checked, they don't.

I would expect they don't fully qualify swap().

| BTW, #4 is more important to me than #3.

Yes, there ought to be some a form of guarantee.


| Fact 5: All this heated debate can be dealt with in one swift stroke.
Simply
| allow partial specialization of function templates. The arguments against
| this so far boil down to

I failed to see any argument against a proposal to allow template
function partial specialization. I would appreciate much you point me
to such a proposal and conter-argument.

| 5.1. This is equivalent to overloading. (It is not. And not only in
| namespace std.)

I would say template function overloading and partial ordering already
offer the effects of a "template function partial specialization". I
would love to be proven wrong on that.


--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gabriel Dos Reis

unread,
Mar 29, 2000, 3:00:00 AM3/29/00
to
Rob Stewart <donot...@giage.com> writes:

| Andrei Alexandrescu wrote:
| >
| > Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
| > news:fl66u9q...@poivre.cmla.ens-cachan.fr...
| >
| > I was willing to drop all this, but I just got a silver opportunity to make
| > some points :o). I have to admit I'm frustrated by this thread, and amazed
| > on such unreasonable things are considered reasonable.
|
| I'm not sure I fully understand what Gabriel (and Siemel) is
| trying to say, but I think I can clarify a couple of points for
| you. (BTW, I understand your confusion. I thought the same
| things as you -- and still think mostly the same. I'm looking
| forward to understanding this stuff more fully.)

I would like to thank Rob for having taken time to explain and to
provide data to illustrate what I was trying to say.

| > > If the library provider felt it necessary to overload std::swap then
| > > surely he would have said so in the documentation. In which case
| > > saying just 'swap' should be sufficient -- or some_author::swap which
| > > I find informative.
| >
| > The problem has to do with uniform call syntax and versioning. "Hey, we just
| > updated our BigNum library. If you used std::swap on BigNums, which worked
| > in the past, that will still work - you see, BigNum still has value
| > semantics - but what you should do is to make a search-and-replace.
| > Otherwise, poor soul, you won't even get a compile-time error; only your
| > programs will run like molasses".
| >
| > I find this unacceptable and it takes me a lot of energy to understand how
| > you anybody else thinks it's acceptable.
|
| I think that here, Gabriel is saying that the user should have
| already been calling "swap" not "std::swap" so there's no
| syntactical change.

Exactly.

[...]


| IOW, when you use scope resolution (std::swap() in the
| discussion), you always get that one. When you don't use scope
| resolution, the compiler selects the best fit. This, of course,
| means that in the scope (possibly namespace scope -- Gabriel's
| point) you must include a using declaration for std::swap() so
| calling swap() *can* invoke std::swap() if appropriate.

Exactly.

I'm also expecting the BigNum library implementor to do something
along the line

#include <algorithm>

namespace N {
class BigNum { /* ... */ };

using std::swap; // may be replaced/overloaded latter with
// customized algorithm.
};

| > I think you will admit now that this fact shatters your whole argument quite
| > strongly.

No, it doesn't.

[...]

| > > | I don't like having to write one using declaration for nearly each of my
| > > | calls to standard library.
| > >
| > > You don't have to.
|
| Gabriel, if I've missed your intent, please explain yourself
| here. Otherwise, this will become a "Yes, I do," "No, you
| don't," kind of argument.

Rob, thank you for taking the challenge to explain what I seemed to
have lots of pain to say. You didn't miss my intent.

| > I have to, if I want to give a crack to specialization, or, if a
| > specialization does not exist, to rely on the default algorithm. *This* is
| > what I want, and I think it's legitimate to want that. In this thread, I
| > don't need solutions to any other problem than this one.
|
| Given implementor prescience, you can get this, but only if you
| don't use scope resolution. As other's have said, however, this
| means that the algorithms' names *must* be treated as sacred in
| all namespaces. That is, *any* non-member function called the
| same as a standard algorithm *must* provide compatible semantics
| with the standard algorithm. This places a serious burden on the
| selection of standard algorithm names and on the names selected
| for non-standard semantics operations that would otherwise be
| named the same.

Yes. And here I think Dave has a good point.

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Gabriel Dos Reis

unread,
Mar 29, 2000, 3:00:00 AM3/29/00
to
Dave Abrahams <abra...@mediaone.net> writes:

| in article fl66u9q...@poivre.cmla.ens-cachan.fr, Gabriel Dos Reis at
| dos...@cmla.ens-cachan.fr wrote on 3/26/00 11:12 PM:
|

| > Programs should behave consistently with their syntactic expression.
| > I know we (you Andrei and me) don't perceive namespaces (especially
| > namespace std), and name lookup from the same point of view. If I say

| > 'std::some_algorithm', then I'm expecting some_algorithm (found by
| > lookup in namespace std) to be that some_algorithm defined by the
| > standard or by the particular implementation I'm using.
|
| Then your expectations might be violated, since the user is allowed to fully
| specialize std::swap<UDT>.

Yes, std::swap() can be explicitly specialized on a UDT, as per the
language rules.

But as I said in another message, I'd expect swap(UDT&, UDT&) to be
defined in UDT's enclosing namespace because it is logically part of
UDT's interface.

|
| This world is much too complicated, IMO.

Yes it is a complicated world, but I think that it can be rationalized
given some discipline.


| > If I say
| > unqualified 'some_algorithm' I'm expecting to get that some_algorithm
| > that happens to fit my data.
|
| Then your expectation might be violated, if your data happens to be made up
| of builtin types. Don't forget, even types in namespaces might be typedefs
| for builtin types.

Yes, I'm not forgetting that point (I just don't know to handle them
correctly :-); builtin types have always been a source of special
cases (e.g. the ad hoc meaning of T())

| > If the author of the library didn't expect std::some_algorithm to be
| > used with his some_author::nifty_data_type then the unqualified
| > some_algorithm() will give me a chance to catch that error at
| > compile-time. If he did,-- because he was careful (or competent?) --
| > he would have inserted the appropriate using-declarations in namespace
| > some_author so that Koenig lookup can find it.
|

| Whew! What happens in this case?
|
| namespace some_author {
| struct nifty_data_type {...}; // swapped fine by std::swap
| using std::swap; // for use on nifty_data_type
|
| .... // much later...
|
| template <class T>
| struct nifty_data_type2 {...}; // needs special swap
| template <class T>
| void swap(nifty_data_type2<T>&, nifty_data_type2<T>&);
| } // namespace some_author

Dave, I failed to understand the point you're raising with this sample
of code. Please, could you elaborate? Thanks.

Gabriel Dos Reis

unread,
Mar 29, 2000, 3:00:00 AM3/29/00
to
"Andrei Alexandrescu" <andre...@hotmail.com> writes:

| Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message

| news:flr9cyo...@poivre.cmla.ens-cachan.fr...
| > "Andrei Alexandrescu" <andre...@hotmail.com> writes:

| > | There's one more thing I don't like about this thread - the attitude
| that
| > | the Standard is perfect and that any criticism to it is an insult.
| >
| > Could you quote any message to that effect?
| >
| > What I have seen so far is:
| > o confusion of concepts -- clarifications have been given.
| > o unfounded claim -- they have been disposed of.
| > o extension proposition.
|
| Ah, what I've seen so far is:

You said you didn't like "the attitude that the Standard is perfect
and that any criticism to it is an insult". I asked you to quote any
message in this thread that supports you claim. You didn't.

| * confusion of concepts - thanks for the clarifications.
|
| * reasonable claims - they have been "disposed of" without any arguments
| that the current scheme has any advantage or usefulness. (I refer to the
| "current scheme" as of the interdiction to overload algorithms in namespace
| std.)
|
| * a proposition to repair something that's utterly broken, fundamentally
| flawed, and a potential source of subtle errors in code that looks
| innocuous, compiles fine, and even runs sometimes (see the exception safety
| issue in another post of mine). The proposition was dismissed by yourself
| for being not that smart, and - worse - ignored by all other participants to
| this newsgroup, who have an influence in changing things.

Could you provide any quote from my postings that might tend to
support such a claim? If you can't then I'd suggest you stick to
facts.

The only I've done so far is to show why I don't beleive in what you
call a defect. Whether it's a potential source of subtile errors is
another debate, IMO. Overloading (in C++) *is* a subtile concept.

Gabriel Dos Reis

unread,
Mar 29, 2000, 3:00:00 AM3/29/00
to
"Ross Smith" <ros...@ihug.co.nz> writes:

| "Gabriel Dos Reis" <dos...@cmla.ens-cachan.fr> wrote in message
| news:flr9cyo...@poivre.cmla.ens-cachan.fr...
| > "Andrei Alexandrescu" <andre...@hotmail.com> writes:
| >

| > | 2. Give someone a library and tell them they must use the following
| idiom:
| > |
| > | {
| > | BigNum a;
| > | using std::some_algorithm;
| > | some_algorithm(a);
| > | }
| > |
| > | in *every* darn place they ever use a standard algorithm on any of
| your
| > | types.
| >
| > BigNum author is supposed to have documented his library. In which
| > case it is known whether or not some_algorithm is part of his library
| > or not. If it is part of the library, then there is no need for the
| > using-declaration. If not the just saying std::some_algotrithm(a) is
| > plain sufficient.
|
| But the point you keep evading is that this approach *doesn't work for
| arbitrary types*. You have to know in advance that the algorithm is

| either in a specific namespace or always in the same namespace as the
| type.
|
| Consider this:


|
| template <typename T> void correct_order(T& t1, T& t2) {
| if (t2 < t1)
| swap(t1, t2);
| }
|
| As written, it won't work if T is a primitive arithmetic type. If swap()
| is replaced with std::swap(), it won't work with a user-defined type
| whose swap() function is in a namespace other than std. If the UDT is a
| template, its swap() can't be put in namespace std because of the ban on
| partial specialisation.
|

| Please explain how to solve this problem. Apparently the rest of us are
| too dumb to figure it out.

Firstly, I don't think you're "too dumb" (despite what others might say
-- or might want me to say :).

Secondly, the problem shows up only in template code. It shows up
because builtin types don't have associated namespaces in Koenig
lookup.

To make the above work properly with any T, you have to insert a
using-declaration:

template<typename T>
void correct_order(T& t1, T& t2)
{
using std::swap;

if (t1 < t2)
swap(t1, t2);
}

I will repeat myself: you have to do this *only* in template code. Not
every time you need to call a standard algorithm because for non
dependent type you know whether it is a builtin type or not.

If T happens to be a fondamental type then std::swap will be
selected. Why do you think it doesn't work?

Andrei Alexandrescu

unread,
Mar 29, 2000, 3:00:00 AM3/29/00
to
Thomas Maeder <mae...@glue.ch> wrote in message
news:38DFDC9D...@glue.ch...

> Before I learnt otherwise in this thread, I thought that it wasn't
possible
> to provide specialized implementations of std algorithms. I would have
> agreed that this was a defect in the language.
>
> But it isn't, as Gabriel has shown me. What you'd like to add to the
> language is not a necessity, but nice to have IMHO. I am not against your
> suggestions, but I don't think that it *has* to fixed as a defect.

Then how do you explain that you still *are* allowed to specialize swap *in
the std namespace*. IOW, how do you intellectually deal with this asymmetry:

* You can specialize every std template class with your types
* You can partially specialize every std template class with your template
classes
* You can specialize every std template function with your types
* You CANNOT overload any std template algorithm with your template classes.
The discussion with using Koenig lookup etc. kicks suddenly up.

It's clear that user-defined template classes have been left out without a
reason. To me it is obvious that this is an oversight, one that should
simply be corrected (as Lisa suggested).

I can't believe, after all that has been said, that anybody coould possibly
sustain that this is the way it was intended. If Koenig lookup was intended
to solve user-defined stuff, why in the world can you specialize std
algorithms right in namespace std?

Why are templates left out? And why do people invest so much effort in
explaining that this is anything else than an obvious little mistake?

But, as I have learned recently that not every burp of mine is wise, I think
I'll drop it.


Andrei

Gabriel Dos Reis

unread,
Mar 29, 2000, 3:00:00 AM3/29/00
to
"Ross Smith" <ros...@ihug.co.nz> writes:

[...]

| ... But I still say it's an ugly and potentially dangerous hack to


| get around the ban on partial specialisation of standard algorithms
| (or partial overloading or whatever the heck it's officially called).

Inheritance without virtual destructor is "potentially dangerous".

Casting is potentially "potentially dangerous".

Public virtual functions are "potentially dangerous".

The two-phase name lookup in templates might be seen as ugly and
potentially dangerous; yet nobody argues it is a defect <g>


void print();

// ...

template<typename T>
struct base { void print() { /* ... */ } };

template<typename T>
struct derived : base<T> {
// ...
void do_something()
{
// ...
print(); // is it clear `print' is not `base<T>::print()?'
// ...
}
};


The point is that it doesn't suffice to repeat it is "dangerous" --
"dangerous" features aren't uncommon in C++; it just depends on ones
definition of "dangerous".

--
Gabriel Dos Reis, dos...@cmla.ens-cachan.fr

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Siemel B. Naran

unread,
Mar 29, 2000, 3:00:00 AM3/29/00
to
On 26 Mar 2000 08:28:55 -0500, Andrei Alexandrescu

>> Notice that declaring a function with the same name in different
namespaces
>> is actually a form of overloading, thanks to Koenig lookup. Example:


>
>Koenig lookup is cool. What I don't like is the impenetrability of
namespace
>std.

Before this thread, I didn't even know that you could specialize anything
in namespace std. I don't think it is a good idea to allow this sort of
thing, be it partial specialization or total specialization or overloading.
Just as the class is the unit of a thought, and can't be reopened and
changed once defined, the namespace is the unit of a collection of
thoughts, and should not be reopened and changed once defined. IOW, the
implementor of namespsace library should be able to forward declare other
entities in namespace library and reopen the namespace and add new
classes and functions to the namespace. But the client of namespace
library should not be able to do any of this. It is too invasive. So
it appears that I am a little behind the times.

I agree with you that if total specialization is allowed, then total
specialization ought to be allowed too. And anyway, I still don't get
the distinction between function specialization and function overloading.

>> Try this analogy. Can we overload functions across the inheritance
>> hierarchy? Yes, if the function is virtual.
>> struct A { virtual void f(); }
>> struct B : A { virtual void f(); }
>> struct C : B { virtual void f(); }
>> void silly(B& b) { b.f(); }
>> The "b.f()" calls either B::f or C::f. But when we call explicitly
>> through
>> the scope resolution operator, as in "b.A::f()" or "b.B::f()", we turn
the
>> virtual function mechanism off, thereby forcing a call to a specific f().
>> Similarly, when we prepend the namespace 'std::', we force a call to a
>> function in a specific namespace, thereby turning the namespace
>> overloading mechanism (ie, Koenig lookup) off.


>
>Sorry, but your analogy doesn't appeal to me. For one thing, I don't have
to
>write "using A::f" before calling b.f().

We can think of the "b." as setting up a bunch of using declarations.

--
--------------
siemel b naran
--------------

Andrei Alexandrescu

unread,
Mar 29, 2000, 3:00:00 AM3/29/00
to
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
news:fl4s9q9...@poivre.cmla.ens-cachan.fr...

> | Fact 5: All this heated debate can be dealt with in one swift stroke.
> Simply
> | allow partial specialization of function templates. The arguments
against
> | this so far boil down to
>
> I failed to see any argument against a proposal to allow template
> function partial specialization. I would appreciate much you point me
> to such a proposal and conter-argument.

I think allowing template function partial specialization (TFPS) is useful,
but I'm afraid it's not very practical. Due to the sophisticated partial
ordering that's already in place, TFPS would introduce more confusion than
clarification. For instance:

// archetypal declaration
template <class T> void Foo(T);
// overloaded leveraging partial specialization
template <class U> void Foo(Container<U>);
// (proposed) partially specialized ???
template <class U> void Foo< Container<U> >(Container<U>);

Hmmm... not too appealing.

I think it's much more lucrative to make the small change that Lisa
Lipincott has made. It's obvious that it's in the spirit of the rule; Lisa's
point corrects the oversight precisely where it was made, and does not incur
cascading changes to the language.

> | 5.1. This is equivalent to overloading. (It is not. And not only in
> | namespace std.)
>
> I would say template function overloading and partial ordering already
> offer the effects of a "template function partial specialization". I
> would love to be proven wrong on that.

Maybe you would, but not by this obnoxious pain in the neck that little
uninspired Andrei is.

Template function partial specialization (TFPS) is needed when the template
parameters are not among the argument list. For instance:

// archetypal declaration
template <class T> void Create();
// (proposed) partially specialized
template <class U> void Create< Container<U> >();

You can't hook Create to do something else for Container<U>. Unless you rely
on the awkward "unused parameter" idiom.

// (fixed) archetypal declaration
template <class T> void Create(T* unused);
// (fixed) overloaded
template <class U> void Create(Container<U>*);

When invoking, you pass a 0, static_cast'ed to the type you need to create.

That's why TFPS is needed.

The only true problem that's somehow linked to TFPS is the inability to
partially specialize a member function of a class template. I tried
repeatedly to make waves about this, but...


Andrei

P.S. Peter, load faster! Their defense is weakening!

Mark Rodgers

unread,
Mar 29, 2000, 3:00:00 AM3/29/00
to
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
news:fl4s9q9...@poivre.cmla.ens-cachan.fr...

> I would say template function overloading and partial ordering already
> offer the effects of a "template function partial specialization". I
> would love to be proven wrong on that.

Consider the following program:

#include <iostream>

template<typename T> class Foo {};

template<typename T>
void f(const T &) { std::cout << "General\n"; }

template <typename T>
void f(const Foo<T> &) { std::cout << "Specialised\n"; }

int main()
{
Foo<int> x;
f(x);
f< Foo<int> >(x);
f<int>(x);
}

With Borland C++Builder 4 this prints out

Specialised
General
Specialised

I do not know if this is correct behaviour (it seems so to me), but if the
"specialisation" was a partial specialisation rather than an overload, I
would expect the first two to print 'Specialised' and the third to be
illegal. I suspect that would have been preferable.

Mark

Peter Dimov

unread,
Mar 29, 2000, 3:00:00 AM3/29/00
to
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote in message
news:fl4s9q9...@poivre.cmla.ens-cachan.fr...

>
> I think there is already a language distinction between
> swap<>(UDT&, UDT&) and swap(UDT<T>&, UDT<T>&).
> The former is an explicit specialization and the latter is an
> overloading. I noticed you said std::swap<UDT<T> >. It isn't
> clear what you meant exactly. In case you meant "a partial
> specialization" that requires yet a another core language change.

In this case, I meant that it is possible to provide a more efficient
std::swap for UDT, but not for UDT<T>. Regardless of how exactly
it is done.

> | Let me expand on this further:
> |
> | Fact 4: There is no way to supply an efficient swap() to std::sort or
> | std::reverse. Not only because of Fact 3, but because std::sort and
> | std::reverse are not required to use swap(), fully qualified or not.
>
> Yes, there a lack of interface documentation here.

Not only that. First, std::sort is not required to use std::swap, and
second,
even if it was required to do so, the user cannot provide an efficient
std::swap
for UDT<T>.

Note that std::sort is required by the current Standard to _not_ use an
unqualified
swap(), as I understand it. If it did, it would be possible to write a
conforming program that breaks std::sort.

> | In fact, in all the implementations I checked, they don't.
>
> I would expect they don't fully qualify swap().

No, they don't use swap() _at all_. They use iter_swap() and the default
iter_swap() does not use swap().

> I failed to see any argument against a proposal to allow template
> function partial specialization. I would appreciate much you point me
> to such a proposal and conter-argument.

I summarized the usual responses to the question "why not allow partial
specialization for template functions" as I remember them from previous
threads. I may have misinterpreted them or missed something. See

http://x46.deja.com/getdoc.xp?AN=555708609

and the corresponding thread.

> | 5.1. This is equivalent to overloading. (It is not. And not only in
> | namespace std.)
>

> I would say template function overloading and partial ordering already
> offer the effects of a "template function partial specialization". I
> would love to be proven wrong on that.

First, partial specializations in std:: are allowed, overloading is not.

Second:

template<class T> void f();
template<class T> void f<T*>(); // not possible with overloading

A workaround does exist - use a wrapper class with a static f(). But what's
more important to me is that I can't see a compelling reason to restrict
partial specialization to template classes.

I understand that this is a core language change and as such is likely to
meet resistance. But:

1) It will not break any existing code, as far as I can see;
2) Allowing std:: overloading is much more dangerous and may have unforeseen
consequences.
3) It would be pointless to "patch" the Standard to fix this particular
std::swap problem unless it is 100% certain that function template partial
specialization would _never_ be part of C++.

The backup plan is to provide class std::swap_traits<T>. It can be partially
specialized.

And, of course, require that all 'reordering' algorithms actually use it.
Aside from performance implications, this allows the user to ensure that
std::sort does not throw.

--
Peter Dimov
Multi Media Ltd.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Francis Glassborow

unread,
Mar 29, 2000, 3:00:00 AM3/29/00
to
In article <slrn8e2q3u....@localhost.localdomain>, Siemel B.
Naran <sbn...@uiuc.edu> writes

>But the client of namespace
>library should not be able to do any of this. It is too invasive. So
>it appears that I am a little behind the times.

So exactly how do you propose that the owner of a UDT specialise a
standard template for it? Remember that however you do it, it must
always be found for the UDT in question, and so must the template class
that it specialises.


Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Francis Glassborow

unread,
Mar 29, 2000, 3:00:00 AM3/29/00
to
In article <flity6v...@poivre.cmla.ens-cachan.fr>, Gabriel Dos Reis
<dos...@cmla.ens-cachan.fr> writes

>The point is that it doesn't suffice to repeat it is "dangerous" --
>"dangerous" features aren't uncommon in C++; it just depends on ones
>definition of "dangerous".

Yes, being born is extremely dangerous. Indeed it appears to be
universally fatal for human beings. No risk, no gain:)

nik...@my-deja.com

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to
In article <fl4s9qa...@poivre.cmla.ens-cachan.fr>,
Gabriel Dos Reis <dos...@cmla.ens-cachan.fr> wrote:
...

> The only I've done so far is to show why I don't beleive in what you
> call a defect. Whether it's a potential source of subtile errors is
> another debate, IMO. Overloading (in C++) *is* a subtile concept.

Perhaps there's an opportunity to find some common ground here.
Let's start with the humble proposition that the current rules
do create the potential for subtle errors, in that calls like
std::swap(a,b) may not always do what some people expect. I
hope we can all agree thus far.

The question then arises, how best to prevent such errors?
Educate, or change the rules? I think reasonable people can
disagree about this.

Education would be valuable in any case. I think there is a
widespread belief that "using namespace std" is bad, "using
std::swap" is better, and qualifying the namespace with each
call is somehow best of all -- without a lot of understanding
of how the meanings of these constructs differ. The idea that
a qualified name imposes a "stricter requirement" than an
unqualified name was not something I had ever thought about
until this discussion.

Still, if a minor change in the rules could actually prevent
such errors without doing other damange, we should at least
consider that option. Lisa Lippinncott suggested changing
17.4.3.1 [lib.reserved.names] to allow overloading function
template declarations in namespace std, subject to the same
restrictions that apply to function template specializations
(which are already allowed).

Personally, I think this amendment would make the rules more
consistent and intuitive than they are now. If we allow
programmers to write their own versions of standard algorithms
for their own non-template types, doesn't it also make sense
to allow it for template types. I don't think allowing this
would open the door for people to pollute the std namespace.

What does this say about the meaning of a qualified name like
std::swap? Even under the current rules, such a name does not
necessarily resolve to a function supplied with the standard
library. I submit that "std::swap" is best thought of as the
name of an algorithm with standard semantics, and for which
the standard library provides a default implementation. This
means if you call std::swap you know what it will do (because
the standard says so), even if the call actually resolves to
a user-defined function.

Of course, even if by some miracle we all agreed that a
change was desirable, there remains the question of whether
the lack of such a provision in the current rules represents
a defect. I really don't know how to answer that one...


Sent via Deja.com http://www.deja.com/
Before you buy.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Peter Dimov

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to
Andrei Alexandrescu <andre...@hotmail.com> wrote in message
news:se33fd...@news.supernews.com...

>
> I think allowing template function partial specialization (TFPS) is
useful,
> but I'm afraid it's not very practical. Due to the sophisticated partial
> ordering that's already in place, TFPS would introduce more confusion than
> clarification. For instance:
>
> // archetypal declaration
> template <class T> void Foo(T);
> // overloaded leveraging partial specialization
> template <class U> void Foo(Container<U>);
> // (proposed) partially specialized ???
> template <class U> void Foo< Container<U> >(Container<U>);
>
> Hmmm... not too appealing.

Ah, that's a good example. It did confuse me for a second. But it's not
ambiguous.

"Doctor, I get confused when I partially specialize and overload at the same
time!"
"Then don't partially specialize and overload at the same time."

> I think it's much more lucrative to make the small change that Lisa
> Lipincott has made. It's obvious that it's in the spirit of the rule;
Lisa's
> point corrects the oversight precisely where it was made, and does not
incur
> cascading changes to the language.

I respectfully disagree. TFPS does not incur any cascading changes to the
language mainly because the infrastructure to support it is already there.
And I can't see how could it possibly break any existing code.

In case TFPS doesn't make it, however, I would go with the less encompassing
solution of std::swap_traits. I am not sure that allowing std:: overloading
wouldn't open an even bigger can of worms.

[...]

> // (fixed) archetypal declaration
> template <class T> void Create(T* unused);

Or, better yet,

template<class T> void Create(T* = 0);

People that have to deal with MSVC are more than familiar with that one.

> P.S. Peter, load faster! Their defense is weakening!

It's not "us vs. them", it's "us vs. the std::swap() problem." :)

The "use unqualified swap()" solution is viable, provided that:

1. swap() is "promoted to operator status" by the Standard, i.e. swap() is
reserved in all namespaces to mean "swap".

2. A default swap() is defined in the global namespace.

3. The offending algorithms are required to use unqualified swap().

BTW is it just me, or would the swap() below really work in 98% of the
cases? (In practice. I know it's undefined behavior in theory.)

template<class T> void swap(T& a, T& b)
{
unsigned char t[sizeof(T)];
memcpy(t, &a, sizeof(T));
memcpy(&a, &b, sizeof(T));
memcpy(&b, t, sizeof(T));
}

--
Peter Dimov
Multi Media Ltd.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Peter Dimov

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to
Andrei Alexandrescu <andre...@hotmail.com> wrote in message
news:se2asis...@news.supernews.com...

> Thomas Maeder <mae...@glue.ch> wrote in message
> news:38DFDC9D...@glue.ch...
> > Before I learnt otherwise in this thread, I thought that it wasn't
> possible
> > to provide specialized implementations of std algorithms. I would have
> > agreed that this was a defect in the language.

It still isn't, unless the implementation uses unqualified swap() - this
makes it
non-conforming under the current rules. At least I think so.

> Then how do you explain that you still *are* allowed to specialize swap
*in
> the std namespace*. IOW, how do you intellectually deal with this
asymmetry:
>
> * You can specialize every std template class with your types
> * You can partially specialize every std template class with your template
> classes
> * You can specialize every std template function with your types
> * You CANNOT overload any std template algorithm with your template
classes.

I don't follow your logic here. You cannot overload with a non-template
either.

Point 4 should read

* You cannot partially specialize any std template algorithm.

Not because the Standard explicitly forbids partial specializations in
std::, but because the core language doesn't allow function template partial
specializations.

The Standard would be perfect in this point as written, had FTPS been legal.

So I think that before discussing "fixes" that, in my opinion, are
unnecessarily broad, "the powers that be" should declare a position on the
FTPS issue. No point in fixing something that is not broken.

Apart from that, would anybody come up with an example where it is necessary
to replace a standard algorithm that is not std::swap or std::iter_swap?

I mean, why open the whole std:: namespace even further if std::swap() is
all we need?

> I can't believe, after all that has been said, that anybody coould
possibly
> sustain that this is the way it was intended.

I agree. The intent of the Standard is clear. Specializations in std:: are
the way to provide more efficient versions of the standard algorithms.

I don't think that anybody sustained the contrary, however.

It is loading more messages.
0 new messages