ADL and friend injection

Consider this code:

template <int N> struct X { friend void f(X *) {} }; int main() { f((X<0> *)0); // Error? } 
Compilers

seem to heavily disagree. (MSVC08 / 10 says no, GCC <4.5 says yes, but 4.5 says no, Sun 5.1 says yes, Intel 11.1 says yes, but goau says no (both are EDG )).

According to "C ++ Templates - The Complete Guide":

... it is assumed that the call including finding friends in related classes is actually the class to be created ... Although this was clearly intended for those who wrote the C ++ standard, this is not clearly stated in the standard.

I could not find the corresponding section in the standard. Any link?

Consider this variation:

 template <int N> struct X { template <int M> friend void f(X<M> *) {} }; template <> struct X<0> { }; int main() { X<1>(); f((X<0> *)0); // Error? } 

The key problem here is that the viable function introduced by X<1> should be visible during ADL for X<0> ? Are they related? All the compilers mentioned above accept this code, with the exception of Comeau, which only accepts it in relaxed mode. Not sure what the standard should say about this.

What do you take on?

+6
c ++ templates argument-dependent-lookup friend-function
source share
1 answer

The standard says in 14.7.1/4

A class template specialization is implicitly created if the class type is used in a context that requires a fully defined object type, or if the completeness of the class type affects the semantics of the program; in particular, if an expression whose type is a specialization of a class template is associated with overload resolution, pointer conversion, pointer to member conversion, specialization of the class template is implicitly created (3.2);

Please note that Vandervoorde made a problem report here and the committee found

The standard already indicates that this creates an instantiation point.

For your second case, you need to consider the related classes and namespaces of the argument f(X<0>*) . This, since this is a pointer to the specialization of the class template (note that the below "id-template" is not entirely correct - C ++ 0x fixed this to use the correct term), as well as a pointer to the class (this tangled split has also been adjusted in C ++ 0x - it lists these two cases at one marker point).

  • If T is an identifier for a template, its associated namespaces and classes are the namespace in which the template is defined; [... a lot of noise ...]

  • If T is a class type (including unions), its associated classes: the class itself; the class of which he is a member, if any; and its direct and indirect base classes. Its associated namespaces are namespaces in which related classes are defined.

So, for summary, we have X<0> as the related classes, and the associated namespaces is the global namespace. Now the friendโ€™s features that are visible,

  • Any namespace name functions declared in related classes are visible within their respective namespaces, even if they are not visible during a normal search

X<0> does not have a friend function, so a friend function declaration is not displayed when viewing the global namespace. Note that X<0> is a completely different type of class than X<1> . The implicit creation of X<1> that you do there does not affect this call - it simply adds an invisible name to the global namespace, which refers to a friend function of class X<1> .

+4
source share

All Articles