Re: Class templates and friend function templates





John Carson wrote:
[...]
> >> It would appear in fact that, where friend declarations
> >> are concerned, partial specialisation is ruled out for
> >> *both* functions *and* classes. This is stated by
> >> Vandevoorde and Josuttis (C++ Templates: The Complete
> >> Guide, p. 117) and experimentation confirms it.

That's correct. The standard says that a friend of a class
or class template can be one of (14.5.3/1):
- a (primary) template (class or function)
- a nontemplate class or function
- a (full) specialization of a template

[...]
> I don't have any problem with that. What is curious is that in
>
> template <class T>
> class C
> {
> public:
> C(int x_) : x(x_) {}
>
> private:
> int x;
>
> template <class Other>
> friend bool operator == (C<T>&, C<Other>&);
> };
>
> operator== does not have two template parameters distinct from the template
> parameter of the enclosing class. It only has one parameter that is
> distinct, thus implying a kind of partial specialisation of the friend
> declaration once C is instantiated for a particular type. If this simply
> didn't compile, then the mystery would disappear. Seemingly, what is
> happening is that the T that appears in C<T>& in the operator's parameter
> list is treated as distinct from the T that is the template parameter for
> the class. But if that is the case, then you would expect that the compiler
> would require:
>
> template <class T, class Other>
> friend bool operator == (C<T>&, C<Other>&);

Not quite. The funny thing about friend declarations is that they are
indeed declarations: They are able to introduce ("inject") a new entity
in the stream of namespace scope declarations. Consider this example:

template<typename T> struct S;
template<typename T, typename U> void f(S<T>*, S<U>*) {} // (1)
template<typename T> struct S {
template<typename U> friend void f(S<T>*, S<U>*); // (2)
};

S<int> s; // (2)

Here, when S<int> gets instantiated (at point (2)), the friend
declaration
gets instantiated with it, and becomes a declaration of the following
template:
template<typename U> void f(S<int>*, S<U>*); // (3)

This is a primary template (there aren't partial specializations of
function
templates anyway) that has no connection to the template declared in
(1),
other than being an overloaded version of it. E.g., assuming an
implementation that uses mangled names, the mangled names for the
instances of (1) and (3) will be different.

Finally, I should note that because (3) was only declared as a friend
declaration, its visibility is limited. For example, if we removed the
declaration (1) (to avoid ambiguities), a call of the form
f(0, (S<float>*)0)
would not find the friend declaration because S<int> isn't an
associated class of either of the arguments (friend declarations are
only visible through a form of argument-dependent lookup).

(See section 9.2.2 in "C++ Templates" for a discussion of this.)

I hope that's helpful somehow.

Daveed

.



Relevant Pages

  • Re: Errors in VC program with gdiplus
    ... template argument list ... : see declaration of 'iterator' ...
    (microsoft.public.vc.mfc)
  • Errors in VC program with gdiplus
    ... template argument list ... : see declaration of 'iterator' ...
    (microsoft.public.vc.mfc)
  • Friend function of a template class
    ... template class. ... MyFriendFunction (MyClass * const ptrMyClass) ... after class declaration. ...
    (comp.lang.cpp)
  • Re: Type intializing with template
    ... There's a syntax error lurking in your code. ... Template definitions and declarations cause mysterious syntax errors. ... the simple error of lacking the template declaration ... > ref class X{ ...
    (microsoft.public.dotnet.languages.vc)
  • Re: Circular Class Template Friendship
    ... > My issue is the syntax of declaring a friend class within ... > which the string is a fixed width that is specialized. ... it is still possible to have Name_Id_Table template ... the friend class declaration. ...
    (comp.lang.cpp)

Loading