There is no convincing technical reason for this. ADL can't find it, you say? Well, that's basically part of the question: why can't ADL find it? Just extend ADL to make it find it.
One design-level reason for this limitation is probably rooted in the language treatment of unqualified names in friend declarations.
Unqualified names used in friend declarations in local classes refer to names from nearest enclosing non-class scope. This treatment of unqualified names is critically important, since this is the only way local classes can refer to each other (since for obvious reasons, local classes do not have qualified names)
int main()
{
class B;
class A {
int x;
friend B; // refers to local `B`
};
class B {
void foo(A &a) { a.x = 42; }
};
}
This rule is also applied to friend function declarations with unqualified names. C++ does not have local functions, but such friend declarations can still refer to a local non-defining declaration of a function (which is perfectly legal)
void foo() {}
int main()
{
void foo(); // refers to `::foo`
class A {
friend void foo(); // refers to local `foo`, which is `::foo`
};
}
Now, what would you propose should happen when one defines a friend function in a local class (using an unqualified name, of course)? What function is introduced by such a declaration? Into what scope, specifically? By definition, it is not a member of the class, since friend declarations do not introduce class members. It cannot be a member of the nearest enclosing local scope, since that would make it a local function and C++ does not support local functions.
We cannot just uniformly change the behavior of all unqualified names in friend declarations and say that they should now refer to names in the nearest enclosing namespace scope, since that would leave as with no way to refer to local classes (as shown above).
The only way out of this situation is to make only in-class friend function definitions refer to (and define) functions in the nearest enclosing namespace scope. Such functions would only be callable through [modified] ADL (and let's say we are OK with that). But that would mean that we'd have to give different treatment to unqualified names in friend function definitions (as opposed to non-defining friend declarations). This would be rather inelegant and confusing. So, the language authors decided against it.
Note that importance of this might have increased notably after C++14, which gave us deduced auto
return types in functions. After that local classes became not even nearly as "local" as they used to be
auto foo()
{
struct S // Local class
{
void bar() {}
};
return S();
}
int main()
{
auto a = foo();
a.bar(); // An object of local class used outside of its original scope
typedef decltype(a) S; // Local type is "stolen" from its original scope
S b; // and used to freely declare objects in a completely
b.bar(); // different scope
}