ambient swap template not found.

K

Kai-Uwe Bux

Hi folks,


I am still struggling with the rules for name lookup.


Please consider:

namespace xxx {

struct empty {};

void swap ( empty & a, empty & b ) {}

template < typename T >
struct stupid {

T data;

void swap ( stupid & other ) { // line 12
swap( this->data, other.data ); // line 13
}

};

}

int main ( void ) {
xxx::stupid< xxx::empty > a, b;
a.swap(b); // line 22
}


The compiler complains:

In member function 'void xxx::stupid<T>::swap(xxx::stupid<T>&)
[with T = xxx::empty]':
file.cc:22: instantiated from here
file.cc:13: error: no matching function for call to
'xxx::stupid<xxx::empty>:
:swap(xxx::empty&, xxx::empty&)'
file.cc:12: note: candidates are: void xxx::stupid<T>::swap(xxx::stupid<T>&)
[with T = xxx::empty]


Obviously, the presence of the local swap-method in stupid<T> prevents the
compiler from looking outside for other possible swaps. I was under the
impression that the namespace where T (in this case xxx::empty) is defined
would be searched for a match. But that apparently does not happen. Why is
that?


Best

Kai-Uwe Bux
 
V

Victor Bazarov

Kai-Uwe Bux said:
I am still struggling with the rules for name lookup.


Please consider:

namespace xxx {

struct empty {};

void swap ( empty & a, empty & b ) {}

template < typename T >
struct stupid {

T data;

void swap ( stupid & other ) { // line 12
swap( this->data, other.data ); // line 13
}

};

}

int main ( void ) {
xxx::stupid< xxx::empty > a, b;
a.swap(b); // line 22
}


The compiler complains:

In member function 'void xxx::stupid<T>::swap(xxx::stupid<T>&)
[with T = xxx::empty]':
file.cc:22: instantiated from here
file.cc:13: error: no matching function for call to
'xxx::stupid said:
swap(xxx::empty&, xxx::empty&)'
file.cc:12: note: candidates are: void
xxx::stupid<T>::swap(xxx::stupid<T>&) [with T = xxx::empty]


Obviously, the presence of the local swap-method in stupid<T>
prevents the compiler from looking outside for other possible swaps.

No, it does not prevent it from looking. It prevents the compiler
from seeing it.
I was under the impression that the namespace where T (in this case
xxx::empty) is defined would be searched for a match. But that
apparently does not happen. Why is that?


It's called "name hiding", I believe. 'swap' name in the struct
'stupid' scope _hides_ the one in the namespace scope, so while
you're in 'xxx::stupid::swap', the other one is simply invisible.

V
 
K

Kai-Uwe Bux

Victor said:
Kai-Uwe Bux said:
I am still struggling with the rules for name lookup.


Please consider:

namespace xxx {

struct empty {};

void swap ( empty & a, empty & b ) {}

template < typename T >
struct stupid {

T data;

void swap ( stupid & other ) { // line 12
swap( this->data, other.data ); // line 13
}

};

}
[snip]
I was under the impression that the namespace where T (in this case
xxx::empty) is defined would be searched for a match. But that
apparently does not happen. Why is that?


It's called "name hiding", I believe. 'swap' name in the struct
'stupid' scope _hides_ the one in the namespace scope, so while
you're in 'xxx::stupid::swap', the other one is simply invisible.


Thanks a lot for the explanation. However, that leaves me with a problem:
how to tell the template stupid<T> which swap to use. I considered:

template < typename T >
struct stupid {

T data;

void swap ( stupid & other ) {
std::swap( this->data, other.data );
}

};

This, I think, will not find specialized/overloaded version of swap for
types not declared in namespace std; and I cannot dump my stuff in there.

Thus, I did:

namespace xxx {

struct empty {};

void swap ( empty & a, empty & b ) {}

template < typename T >
void global_swap ( T & a, T & b ) {
swap( a, b );
}

template < typename T >
struct stupid {

T data;

void swap ( stupid & other ) {
global_swap( this->data, other.data );
}

};

}

This will find the appropriate swap by looking at the argument type. But
introducing the forwarding function "global_swap" seems clumsy. I would
appreciate suggestions for how to improve upon this.


Thanks again

Kai-Uwe Bux
 
V

Victor Bazarov

Kai-Uwe Bux said:
[..]
Thanks a lot for the explanation. However, that leaves me with a
problem: how to tell the template stupid<T> which swap to use. I
considered:

template < typename T >
struct stupid {

T data;

void swap ( stupid & other ) {
std::swap( this->data, other.data );
}

};

This, I think, will not find specialized/overloaded version of swap
for types not declared in namespace std; and I cannot dump my stuff
in there.

Yes, you can.

"17.4.3.1 Reserved names
[...]. A program may add template specializations for any
standard library template to namespace std. [...]"

So, you're totally allowed to specialise 'swap' for your class 'empty'
and put it in 'std' namespace.

V
 
J

Jon Slaughter

Kai-Uwe Bux said:
Hi folks,


I am still struggling with the rules for name lookup.


Please consider:

namespace xxx {

struct empty {};

void swap ( empty & a, empty & b ) {}

template < typename T >
struct stupid {

T data;

void swap ( stupid & other ) { // line 12
swap( this->data, other.data ); // line 13
}

how bout xxx::swap instead?

Jon
 
J

Jon Slaughter

Victor Bazarov said:
That would not allow using 'std::swap' for T other than 'empty'.

V

Then he needs to specialize stupid::swap if T is of empty type to use
xxx::swap?

basicaly

if T is of type empty then use xxx::swap else use std::swap

or whatever
 
K

Kai-Uwe Bux

Victor said:
Kai-Uwe Bux said:
[..]
Thanks a lot for the explanation. However, that leaves me with a
problem: how to tell the template stupid<T> which swap to use. I
considered:

template < typename T >
struct stupid {

T data;

void swap ( stupid & other ) {
std::swap( this->data, other.data );
}

};

This, I think, will not find specialized/overloaded version of swap
for types not declared in namespace std; and I cannot dump my stuff
in there.

Yes, you can.

"17.4.3.1 Reserved names
[...]. A program may add template specializations for any
standard library template to namespace std. [...]"

So, you're totally allowed to specialise 'swap' for your class 'empty'
and put it in 'std' namespace.

Great! Thanks for that crucial piece of information.


Best

Kai-Uwe Bux
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top