views:

58

answers:

1

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 too but comeau says no (both are EDG)).

According to "C++ Templates - The complete guide":

... it is assumed that a call involving a lookup for friends in associated classes actually causes the class to be instantiated ... Although this was clearly intended by those who wrote the C++ standard, it is not clearly spelled out in the standard.

I couldn't find the relevant section in the standard. Any reference?

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 issue here is wether the viable function injected by X<1> should be visible during ADL for X<0>? Are they associated? All compilers mentioned above accept this code, except for Comeau which only accepts it in relaxed mode. Not sure what the standard has to say about this either.

What's your take on that?

+3  A: 

The Standard says at 14.7.1/4

A class template specialization is implicitly instantiated if the class type is used in a context that requires a completely-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 class template specialization is involved in overload resolution, pointer conversion, pointer to member conversion, the class template specialization is implicitly instantiated (3.2);

Note that Vandervoorde made an issue report here, and the committee found

The standard already specifies that this creates a point of instantiation.

For your second case - you need to consider the associated classes and namespaces of the argument f(X<0>*). These are, since this is a pointer to a class template specialization (note that "template-id" below is not quite correct - C++0x corrected that to use the correct term) and also a pointer to a class (this confusing split was also corrected in C++0x - it lists these two cases in one bullet point).

  • If T is a template-id, its associated namespaces and classes are the namespace in which the template is defined; [... lots of noise ...]

  • 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 namespaces in which its associated classes are defined.

So to summary, we have as associated classes are X<0> and the associated namespaces are the global namespace. Now the friend functions that are visible are

  • Any namespace-scope friend functions declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup

There is no friend function declared in X<0> so the friend function declaration is not visible when looking into the global namespace. Note that X<0> is an entirely different class-type than X<1>. The implicit instantiation of X<1> you do there has no effect on this call - it just adds a non-visible name into the global namespace that refers to a friend function of class X<1>.

Johannes Schaub - litb
Should the first example be compilable then?
jpalecek
Thanks :) This is more or less what I suspected. How come so many compilers get that second case wrong? Also, I'd appriciate it if you could give references into the standard for the other quotes too.
uj2
@uj2 well, at least clang keeps looking good in comparison to GCC. It correctly rejects the second case. Especially GCC has quite a bit of template conformance issues so this doesn't surprise me. What are the other quotes you are trying to find Standard paragraphs for?
Johannes Schaub - litb
@jpalecek yes the first example should compile.
Johannes Schaub - litb
@litb: clang fails the first one though, and also fails to find friends which are themselves templates... I was referrning to the last two quotes: "If T is a template-id..." and "Any namespace-scope friend..."
uj2
@uj2 aww right, i didn't test case 1 using it :) The quotes are from 3.4.2/2.
Johannes Schaub - litb