Reputation: 325
A friend function named test() is defined inside a template class A:
template <typename T> class A {
public:
friend void cs() {/* code */}
}
Another class inherits from template class A:
class B : public A<B> {}
In main function, I failed to call cs(), the compiler can not see its declaration if I don't provide a function declaration in the global scope:
int main(){
cs()
}
But things are different when cs takes its template class T as an argument:
template <typename T> class A{
public:
friend void cs(const T& t) {}
}
Now cs() can be successfully called in the main function without any decalration:
int main(){
B b;
cs(b);
}
If a function takes a user-defined class as its argument, I know the compiler would search the scope of the user-defined class. So which scope exactly is cs() defined? How it is possible that cs() is successfully called in the second case?
Upvotes: 5
Views: 151
Reputation: 173044
Note that the name cs
introduced by friend declaration is not visible to ordinary name lookup; that's why the 1st case fails unless you provide a declaration at namespace scope.
A name first declared in a friend declaration within class or class template X becomes a member of the innermost enclosing namespace of X, but is not visible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at the namespace scope is provided
And the name cs
is found successfully in the 2nd case because of ADL; you specify a parameter for cs
.
Argument-dependent lookup, also known as ADL, or Koenig lookup, is the set of rules for looking up the unqualified function names in function-call expressions, including implicit function calls to overloaded operators. These function names are looked up in the namespaces of their arguments in addition to the scopes and namespaces considered by the usual unqualified name lookup.
And
So which scope exactly is cs() defined?
The name cs
become members of the innermost enclosing namespace of A
, i.e. the global namespace here, but it's not visible for ordinary name lookup.
Upvotes: 3
Reputation: 170299
If a function takes a user-defined class as its argument, I know the compiler would search the scope of the user-defined class. So which scope exactly is cs() defined? How it is possible that cs() is successfully called in the second case?
You are describing argument dependent lookup here. And that's exactly how cs
is found.
cs
is in the same namespace that A<B>
is defined it, i.e, the namespace and scope of A
.
For the purposes of ADL, an implementation collects "associated namespaces". Those include the namespaces of base classes too.
[basic.lookup.argdep]
2.2 If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the innermost enclosing namespaces of its associated classes. Furthermore, if T is a class template specialization, its associated namespaces and classes also include: the namespaces and classes associated with the types of the template arguments provided for template type parameters (excluding template template parameters); the namespaces of which any template template arguments are members; and the classes of which any member templates used as template template arguments are members. [ Note: Non-type template arguments do not contribute to the set of associated namespaces. — end note ]
Upvotes: 1
Reputation: 49028
If a function takes a user-defined class as its argument, I know the compiler would search the scope of the user-defined class.
Yes, it's called ADL. When you write cs(b)
, the compiler searches for a function named cs
. It can't find any, which is what is happening in your first example.
But now since cs
takes a b
, the compiler can also search b
's scope for a function named cs
. That wasn't possible in the first example because there were no parameters! In B
it finds void cs(const B&)
and so uses that.
So which scope exactly is cs() defined?
In the global scope but cs
is not visible to name lookup without ADL.
How it is possible that cs() is successfully called in the second case?
As explained, cs
can be found through ADL on B
.
Upvotes: 6