问题
#include <iostream>
struct H
{
void swap(H &rhs);
};
void swap(H &, H &)
{
std::cout << "swap(H &t1, H &t2)" << std::endl;
}
void H::swap(H &rhs)
{
using std::swap;
swap(*this, rhs);
}
int main(void)
{
H a;
H b;
a.swap(b);
}
And this is the result:
swap(H &t1, H &t2)
In the code above, I try to define a swap function of H
. In the function void H::swap(H &rhs)
, I use an using declaration to make the name std::swap visible. If there isn't an using declaration, the code cannot be compiled because there is no usable swap function with two parameters in class H
.
I have a question here. In my opinion, after I used the using declaration -- using std::swap
, it just make the std::swap -- the template function in STL visible. So I thought that the swap in STL should be invoked in H::swap()
. But the result showed that the void swap(H &t1, H &t2)
was invoked instead.
So here is my question:
- Why can't I invoke swap without a using declaration?(I guess it is because there is no swap function with two parameters in the class. But I am not sure. )
- Why will the swap of my definition be invoked instead of the STL swap in the
H::swap
?
回答1:
- Why can't I invoke swap without a using declaration?
We start in the nearest enclosing scope and work our way outwards until we find something. With this:
void H::swap(H &rhs)
{
swap(*this, rhs);
}
Unqualified swap
finds H::swap()
. Then we do argument-dependent lookup. But the rule there is, from [basic.lookup.argdep]:
Let X be the lookup set produced by unqualified lookup (3.4.1) and let Y be the lookup set produced by argument dependent lookup (defined as follows). If X contains
— a declaration of a class member, or
— a block-scope function declaration that is not a using-declaration, or
— a declaration that is neither a function or a function template
then Y is empty. Otherwise Y is the set of declarations found in the namespaces associated with the argument types as described below. [...]
Since the unqualified lookup set finds a class member, the argument-dependent lookup set is empty (that is, it doesnt find swap(H&, H&)
).
- Why will the swap of my definition be invoked instead of the STL swap in the
H::swap
?
When you add:
void H::swap(H &rhs)
{
using std::swap;
swap(*this, rhs);
}
now unqualified swap
finds std::swap()
and not H::swap()
, since the former is declared in a more inner scope. using std::swap;
does not match any of the criteria in the above-stated rule that would lead to Y being empty (it's not a class member, it is a using-declaration, and it is a function template). As a result, the argument-dependent lookup set does include declarations found in associated namespaces - which includes swap(H&, H&)
(since H
is in the global namespace). We end up with two overload candidates - and yours is preferred since it's the non-template.
See Xeo's answer on the preferred way to add swap to your class. Basically, you want to write:
struct H {
friend void swap(H&, H&) { ... }
};
This will be found by ADL (and only by ADL). And then whenever anybody calls swap correct:
using std::swap;
swap(a, b);
Lookup will find yours where appropriate.
来源:https://stackoverflow.com/questions/35894955/name-hiding-by-using-declaration