Difference between a pointer to a standalone and a friend function
What I'm missing?
An inline friend declaration does not make the function available to ordinary name lookup.
Pay close attention to the error. It does not say that the function is of the wrong type, it simply can't find anything named operator==
. This is by design.
Inline friend definitions are only found by argument dependent lookup. Ordinary lookup (such as naming the function to take its address), cannot find it. If you want the function to be available for that purpose, you must provide a namespace scoped declaration.
class X {
public:
friend bool operator==(int, X const &) { /* ... */ }
};
bool operator==(int, X const &);
From the standard 11.9.3.7:
Such a function is implicitly an inline ([dcl.inline]) function if it is attached to the global module. A friend function defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not ([basic.lookup.unqual]).
From the standard namespace.memdef/3: (Thanks @StoryTeller)
If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup ([basic.lookup.unqual]) or qualified lookup ([basic.lookup.qual]). [ Note: The name of the friend will be visible in its namespace if a matching declaration is provided at namespace scope (either before or after the class definition granting friendship). — end note ] If a friend function or function template is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments ([basic.lookup.argdep]). If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace.
The following doesn't work because the function is not visible in the current scope.
static_cast<bool (*)(int, X const &)>(&operator==); // Error: 'operator==' not defined
The difference is that in the first snippet you only declare the operator in the scope of X
, but not outside. There is no operator==(int,X const &)
accesible from main
. If you fix that and do declare it also outside you only get warnings:
class X {
public:
friend bool operator==(int, X const &);
};
bool operator==(int,X const&); // <--
int main() {
2 == X(); // ok...
static_cast<bool (*)(int, X const &)>(&operator==); // Error: 'operator==' not defined
return 0;
}
Note however, that for both cases you do need a definition to actually call the operator.
For illustration consider that with
struct foo {
friend void bar() {
std::cout << "this is a inline definition of friend funtion";
}
};
The only way to access bar
from outside foo
is to add a declaration outside of foo
:
void bar();