C++ Logo

std-discussion

Advanced search

Re: hidden friends and member functions

From: Federico Kircheis <federico_at_[hidden]>
Date: Mon, 10 Oct 2022 23:11:28 +0200
On 10/10/2022 23.00, Edward Catmur wrote:
>
>
> On Mon, 10 Oct 2022 at 21:07, Federico Kircheis via Std-Discussion
> <std-discussion_at_[hidden]
> <mailto: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
> <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
> <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
> --


Thank you Edward for the reference to the relevant part of the standard,
very appreciated.

I'll write the workaround with "namespace spoiler { void bar(); }" down,
it works as advertised.

It's not a "local solution", but at least I do not need to define a
dummy function, which is not always that easy if one considers templated
code, perfect forwarding, ....


Which makes me realize, I can write


auto& f2 = mf; [&f2]{void bar(ns::foo&); bar(f2);}();

But only works if the function signature is the correct one.
For example

auto& f2 = mf; [&f2]{void bar(); bar(f2);}();

does not seem to work, even if I would have expected it (and hoped), as
"spoiler::bar" also does not have the right function signature.

Received on 2022-10-10 21:11:33