![](https://fl0w.cc/pictrs/image/9f0c38e9-11be-44b6-b3da-b6b8c6e279c4.png)
I think the issue is that Foo
is incomplete when you’re declaring the friend, so I think it’s impossible. I just tried it and g++ ignores the target candidate due to “member access into incomplete type”, which makes sense since std::begin
is already defined and calls .begin()
. The closest you can get is to use another friend to expose arr
and overload std::begin
manually, but that’s a bit silly 😅
Ah, nice idea. I’ve tried a few different ways of doing this, and I think what you’re seeing is a discrepancy in how the compiler handles member access into incomplete types. It seems that, in your examples, the compiler is allowing
-> decltype(f.private_msg)
within the class, but I think it’s not selectingdo_something
outside of it because it usesdecltype(t.private_msg)
. In my case, I’m not even able to do that within the class.For example, since I’m not able to use
decltype(f.private_msg)
inside the class, I’m usingdecltype(private_msg)
instead, which causes an error at thedo_something
declaration related to incomplete type (presumably because of thet.private_msg
usage):// candidate template ignored; member access into incomplete type template 〈class T〉 auto do_something(T &t) -> decltype(t.private_msg); class Foo { const char *private_msg = "You can't touch me!"; friend auto do_something〈〉(Foo &f) -> decltype(private_msg); }; template 〈〉 auto do_something(Foo &f) -> decltype(f.private_msg) { return f.private_msg; }
My reasoning is that removing the
t.private_msg
from the declaration works:template 〈class Ret, class T〉 auto do_something(T &t) -> Ret; class Foo { const char *private_msg = "You can't touch me!"; friend auto do_something〈〉(Foo &f) -> decltype(private_msg); }; template 〈〉 auto do_something(Foo &f) -> decltype(f.private_msg) { return f.private_msg; } static Foo foo{}; // this works, but Ret cannot be deduced and must be specified somehow: static auto something = do_something〈const char*〉(foo);
The reason your second example works is because the friend template inside the class acts as a template declaration rather than a specialization, which isn’t specialized until after
Foo
is complete:// the do_something inside Foo is a declaration, meaning this isn't used // template 〈class T〉 // auto do_something(T &t) -> decltype(t.private_msg); class Foo { const char *private_msg = "You can't touch me!"; template 〈class T〉 // t.private_msg is allowed because T is not Foo yet friend auto do_something(T &t) -> decltype(t.private_msg); }; template 〈〉 auto do_something(Foo &f) -> decltype(f.private_msg) { return f.private_msg; }