The argument dependent lookup is introduced for unqualified name lookup of all functions not only of friend functions of classes.
Here is a demonstrative program
#include <iostream>
namespace N1
{
struct A
{
int a = 10;
friend void f( A &a ) { std::cout << "friend f( A & ) : A::a = " << a.a << '\n'; }
};
void f( const A &a ) { std::cout << "f( const A & ) : A::a = " << a.a << '\n'; }
}
int main()
{
N1::A a1;
f( a1 );
const N1::A a2;
f( a2 );
N1::f( a1 );
}
The program output is
friend f( A & ) : A::a = 10
f( const A & ) : A::a = 10
f( const A & ) : A::a = 10
In this program when the qualified name lookup is used for a function with the name f and non-constant object a1 as its argument there is called the non-friend function f because the name of the friend function f is invisible in the namespace where its declaration is introduced.
Friend functions are included in the ADL because if a friend function is declared (and correspondingly defined) only in a class its name is invisible in the namespace where the declaration is introduced opposite to functions that declared in the namespace. So non-friend functions for example can be called using qualified names while friend functions that are only declared in classes can not be called using qualified names because they are invisible.
To achieve the same action with non-friend functions you have to make them at first invisible in the namespace where their declarations are introduced and the qualified name lookup shall not find them. It is impossible without introducing in the C++ Standard some new notions.
friend
keyword is to make the function ADL-only. – Watercool