C++ Logo

STD-DISCUSSION

Advanced search

Subject: Re: Member function, using, and ADL
From: Ville Voutilainen (ville.voutilainen_at_[hidden])
Date: 2021-05-29 10:22:39


On Sat, 29 May 2021 at 18:01, Ville Voutilainen
<ville.voutilainen_at_[hidden]> wrote:
>
> On Sat, 29 May 2021 at 17:36, Yongwei Wu via Std-Discussion
> <std-discussion_at_[hidden]> wrote:
> >
> > I happened to find Alan Griffiths' article ‘C++ Standards - The "swap" Problem"’ (<URL:https://accu.org/journals/overload/9/41/griffiths_466/>), and I did some tests while reading it. I was happy and surprised to find what he described seemed a non-issue now.
> >
> > I tested with the following code:
> >
> > #include <iostream>
> > #include <utility>
> >
> > namespace Impl {
> >
> > struct A {
> > int value;
> > };
> >
> > void swap(A& x, A& y)
> > {
> > std::cout << "Impl::A::swap\n";
> > std::swap(x, y);
> > }
> >
> > }
> >
> > namespace App {
> >
> > struct Obj {
> > void swap(Obj& rhs);
> > Impl::A a_value;
> > };
> >
> > void Obj::swap(Obj& rhs)
> > {
> > using std::swap; // NB this line
> > swap(a_value, rhs.a_value);
> > }
> >
> > void swap(Obj& lhs, Obj& rhs)
> > {
> > lhs.swap(rhs);
> > }
> >
> > }
> >
> > int main()
> > {
> > App::Obj a, b;
> > swap(a, b);
> > }
> >
> > I have found out that an error will occur without the ‘using std::swap;’ line, but with it ADL will be in effect and find Impl::A::swap.
> >
> > The interesting thing is that I do not need to write `using Impl::swap;`—it seems any using of non-member functions will enable ADL. But I do not know why.
> >
> > I have looked up the C++ standard and the cppreference.com web site, but failed to find the exact paragraph that dictates this behaviour. Anyone here knows which rules in C++ make this possible?
>
> The thing here is that you can write 'using Impl::swap;' instead of
> 'using std::swap;' on the "NB" line and the example still works
> just fine. The problem with not having any using-declaration there is
> that an unqualified call to swap will try to call the member
> function itself, recursively, and lookup will look no further. ADL
> would work fine for any other name without the using-declaration,
> but it won't work for the name swap - unless you bring *any* function
> candidate name into scope. It doesn't need to be the one called,
> it doesn't even need to be viable, and ADL will be used once such a
> second candidate is in scope, so as to disable the
> name lookup shortcut that looks no further than the member function
> itself. See this:
> https://wandbox.org/permlink/qsrmhp1ddzBQgRjR

And for what it's worth, the rule is at
http://eel.is/c++draft/basic.lookup.argdep#1

Let's run through it:

>unqualified lookup ([basic.lookup.unqual]) for the name in the unqualified-id does not find any
>declaration of a class member, or

Lookup doesn't find the member any more, because it finds the
using-declaration and stops. So now ADL
is enabled.

>function declaration inhabiting a block scope, or

..and wasn't disabled because we wrote a using-declaration, not a
block-scope function declaration..

>declaration not of a function or function template

..and since we did declare a function, ADL remains enabled. If I do
using swap = int; in CompletelyUnrelated,
ADL is disabled because the using-declaration declares a non-function.
But as long as it declares a function,
even if non-viable, ADL is enabled, and is not disabled by finding the member.

Disclaimer: I'm no name lookup expert, but this seems like a plausible
explanation of how the rule works. :P


STD-DISCUSSION list run by std-discussion-owner@lists.isocpp.org

Older Archives on Google Groups