C++ Logo

std-discussion

Advanced search

Re: hidden friends and member functions

From: Edward Catmur <ecatmur_at_[hidden]>
Date: Mon, 10 Oct 2022 22:00:53 +0100
On Mon, 10 Oct 2022 at 21:07, Federico Kircheis via Std-Discussion <
std-discussion_at_[hidden]> wrote:

> If this is the wrong mailing list, sorry, maybe you can redirect me to
> the correct one.
>

Yes, this is the right place.


> Consider following program.
>
>
> ----
> namespace ns{
> struct foo{
> friend void bar(const foo&){}
> };
> }
>
> void bar2(ns::foo& f){
> bar(f);
> }
>
> auto lambda = [](ns::foo& f_){bar(f_);};
>
> struct foo2{
> ns::foo mf;
> void bar(){
> bar(this->mf); // (1)
> auto& f2 = mf; [&f2]{bar(f2);}(); // (2)
> [](ns::foo& f_){bar(f_);}(mf); // (3)
> bar2(mf); // (4)
> lambda(mf); // 5
> ns::bar(mf); // (6)
> ::bar(mf); // (7)
> }
> };
> ----
>
> 1) does not compile, tries to call this->bar, no great, but OK
>
> 2,3) Still tries to call this->bar, even if this has not been captured
>
> 4,5) Works
>
> 6,7) do not compile, as expected
>
> (tested with GCC, clang and MSVC)
>
>
> I understand why 1,4,5,6,7 behave as they do, but fail to see why 2 and
> 3 should not compile and call the hidden friend function.
>

Name lookup proceeds through parent scopes before considering ADL.
https://eel.is/c++draft/basic.lookup#unqual-2.sentence-2
The parent scope of a lamba scope is the scope that contains it.
http://eel.is/c++draft/basic.scope#scope-2.1


> 4 and 5 are suboptimal workarounds because they need a new function, if
> the code is templated it needs to go in the header file, and thus leak
> an implementation detail, if 2 or 3 would work it would be possible to
> keep the workaround local.
> Or is there another way to tell the compiler not trying to call
> this->bar, without resorting to 6,7 as they do not work in this case?
>

Yes, you can bring another namespace scope function `bar` into scope, then
ADL will be considered (because the lookup set does not contain member
functions).

namespace spoiler { void bar(); }
// ...
         auto& f2 = mf; [&f2]{using spoiler::bar; bar(f2);}(); // (2)

It's not a fully local solution, but `::spoiler::bar()` does not need to be
defined or to know anything about `::ns::foo`.

I tried finding the relevant part in the standard why 2 and 3 do not
> work, but failed to do so, can anyone pinpoint me in the right direction?
>
> Best
>
> Federico
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>

Received on 2022-10-10 21:01:07