I have a class template like this:

template< typename t >
class c;

I'd also like to have an operator == for objects of types, which are different specializations of c:

template< typename t1, typename t2 >
bool operator ==
(
s< t1 > const&
, s< t2 > const&
);

In order to implement this operator, I need it to be a friend of both s< t1 > and s< t2 >. For the sake of safety, I'd like no other
specialization of c to have this operator as its friend. Is this possible and, if so, how?

Re: Class templates and friend function templates by Carl

Carl
Sat Jul 23 17:50:56 CDT 2005

BigMan wrote:
> I have a class template like this:
>
> template< typename t >
> class c;
>
> I'd also like to have an operator == for objects of types, which are
> different specializations of c:
> template< typename t1, typename t2 >
> bool operator ==
> (
> s< t1 > const&
> , s< t2 > const&
> );
>
> In order to implement this operator, I need it to be a friend of both
> s< t1 > and s< t2 >. For the sake of safety, I'd like no other
> specialization of c to have this operator as its friend. Is this
> possible and, if so, how?

Like this:

// Code
template <class T> class C;

template <class U, class V> bool operator ==(C<U>,C<V>);

template <class T> class C
{
public: C(int x_) : x(x_) {}

private: int x;

template <class U,class V>
friend bool operator == <T>(U u, V v);
};

template <class U, class V>
bool operator == (C<U> u, C<V> v)
{
return u.x == v.x;
}

int main()
{
C<int> c1(1);
C<float> c2(2);
bool b = c1 == c2;
}
// End of code

I'm actually not sure that this code is standard conforming, although it
seems like it should be. VC 7.1 likes it, but Comeau claims that the
template friend declaration is ill-formed.

-cd





Re: Class templates and friend function templates by Carl

Carl
Sat Jul 23 18:35:59 CDT 2005

Carl Daniel [VC++ MVP] wrote:

> template <class U,class V>
> friend bool operator == <T>(U u, V v);

should be:

template <class U,class V>
friend bool operator == <T>(C<U> u, C<V> v);

Oddly, VC++ likes it either way, Comeau likes neither. More than likely
it's a VC bug that this code compiles (and appears to behave as desired).

-cd



Re: Class templates and friend function templates by John

John
Sat Jul 23 19:49:29 CDT 2005

"Carl Daniel [VC++ MVP]"
<cpdaniel_remove_this_and_nospam@mvps.org.nospam> wrote in message
news:envtI99jFHA.3936@TK2MSFTNGP10.phx.gbl
> Carl Daniel [VC++ MVP] wrote:
>
>> template <class U,class V>
>> friend bool operator == <T>(U u, V v);
>
> should be:
>
> template <class U,class V>
> friend bool operator == <T>(C<U> u, C<V> v);
>
> Oddly, VC++ likes it either way, Comeau likes neither. More than
> likely it's a VC bug that this code compiles (and appears to behave
> as desired).
> -cd


Hi Carl,

I have been playing with this for the past several hours.

Your code can be made to compile on Comeau if you make the friend
declaration as follows:

template <class U,class V>
friend bool operator ==(C<U> u, C<V> v);

i.e., ditch the <T> (of course, one would normally use references).

I presume that your use of <T> is meant to tie friendship to an "own"
instantiation of the class. The following attempts to make such a tie. It
compiles on both Comeau and VC++ 8.0 Beta 2, but fails to enforce the tie
(see below):

template <class T>
class C;

template <class U, class V>
bool operator ==(C<U>&,C<V>&);

template <class T>
class C
{
public:
C(int x_) : x(x_) {}

private:
int x;

template <class Other>
friend bool operator == (C<T>&, C<Other>&);
};

template <class U, class V>
bool operator == (C<U>& u, C<V> &v)
{
return u.x == v.x;
}

int main()
{
C<int> c1(1);
C<float> c2(2);
bool b = c1 == c2;
return 0;
}

The thing that puzzled me is this. When c1 is declared, I expected the
friend declaration to resolve to:

template<class Other>
friend bool operator == (C<int>&, C<Other>&);

as a friend of C<int>. When c2 is declared, I expected the friend
declaration to resolve to:

template<class Other>
friend bool operator == (C<float>&, C<Other>&);

as a friend of C<float>.

When c1 == c2 is evaluated, the operator called is:

bool operator == (C<int>&, C<float>&);

From what I have said above, I expected this to be a friend of C<int>
but not of C<float>. Yet it is apparently a friend of both according to both
Comeau and VC++.

Further experimentation shows that the tying doesn't actually work at all.
If I define a global variable

C<int*> c0(0);

then I can access its private data inside the assignment operator called on
c1 and c2 even though c0 is of a different type to both c1 and c2.

It would seem that my expectations concerning what friend declarations
resolve to were mistaken. This may be because

template<class Other>
friend bool operator == (C<int>&, C<Other>&);

would represent a kind of partial specialisation.

I would be grateful for any insight you might offer.

--
John Carson


Re: Class templates and friend function templates by John

John
Sat Jul 23 20:10:04 CDT 2005

Please don't multi-post. It means people may spend time answering you in one
newsgroup when the question has already been answered in another.

"BigMan" <fn42551@fmi.uni-sofia.bg> wrote in message
news:OsiOF67jFHA.2920@TK2MSFTNGP14.phx.gbl
> I have a class template like this:
>
> template< typename t >
> class c;
>
> I'd also like to have an operator == for objects of types, which are
> different specializations of c:
> template< typename t1, typename t2 >
> bool operator ==
> (
> s< t1 > const&
> , s< t2 > const&
> );

You seem to have switched from c to s.

> In order to implement this operator, I need it to be a friend of both
> s< t1 > and s< t2 >. For the sake of safety, I'd like no other
> specialization of c to have this operator as its friend. Is this
> possible and, if so, how?

The value of this safety is not clear (if you just made the arguments const,
then that should give you all the safety you need). But let's look at it as
an exercise anyway.

One way to do it is to define specialisations of s for t1 and t2 and to make
the appropriate operator a friend of those specialised classes, e.g.,

#include <iostream>
using namespace std;

template<typename t>
class s
{
t data;
public:
s(const t & arg) : data(arg)
{}
};


template <typename t1, typename t2>
bool operator==(s<t1> & lhs, s<t2> & rhs)
{
return lhs.data == rhs.data;
}

template<>
class s<int>
{
int data;
public:
friend bool operator==<int,double>(s<int> & lhs, s<double> & rhs);
friend bool operator==<double,int>(s<double> & lhs, s<int> & rhs);
s(const int & arg) : data(arg)
{}
};

template<>
class s<double>
{
double data;
public:
friend bool operator==<int,double>(s<int> & lhs, s<double> & rhs);
friend bool operator==<double,int>(s<double> & lhs, s<int> & rhs);
s(const double & arg) : data(arg)
{}
};


int main()
{
s<int> s_int(5);
s<double> s_double (5.0);
if(s_int == s_double)
cout << "Equal\n";
else
cout << "Unequal\n";
return 0;
}

If your classes are large and/or you have a lot of specialised cases to
consider, you might wish to save yourself some typing by using inheritance
whereby most of s is put in one or more base classes, the rest of s is in a
derived class, and you specialise the derived class (in particular, you make
friend declarations in the derived class).


--
John Carson


Re: Class templates and friend function templates by Alex

Alex
Sun Jul 24 06:37:20 CDT 2005

John Carson wrote:
> [...]
> The thing that puzzled me is this. When c1 is declared, I
> expected the friend declaration to resolve to:
>
> template<class Other>
> friend bool operator == (C<int>&, C<Other>&);
>
> as a friend of C<int>. When c2 is declared, I expected
> the friend declaration to resolve to:
>
> template<class Other>
> friend bool operator == (C<float>&, C<Other>&);
>
> as a friend of C<float>.
>
> When c1 == c2 is evaluated, the operator called is:
>
> bool operator == (C<int>&, C<float>&);
>
> From what I have said above, I expected this to be a
> friend of C<int>
> but not of C<float>. Yet it is apparently a friend of
> both according to both Comeau and VC++.

The confusion stems from the expectation that function
template instantiation is similar to class template
instantiation. Actually, they're quite different. Class
templates support partial specialization. Partially
spesialized type of class participates in type resolution on
par with primary template.

Function template doesn't support partial specialization.
Function templates can overload each other, though.
Therefore, when compiler search for suitable function
template it doesn't distinguish between

bool operator == (C<int>&, C<Other>&);

and

bool operator == (C<float>&, C<Other>&);

All what compiler sees is:

template <class U, class V>
bool operator ==(C<U>&,C<V>&);

That is, _each_ specialization of class C will have _all_
specializations of operator == as friend. Only then, when
choice is locked (i.e., appropriate instance of operator ==
is generated), will compiler check for any particular
specialization of operator ==.

> Further experimentation shows that the tying doesn't
> actually work at all. If I define a global variable
>
> C<int*> c0(0);
>
> then I can access its private data inside the assignment
> operator called on c1 and c2 even though c0 is of a
> different type to both c1 and c2.

Yes, this happens because given template arguments

template <class U, class V>

will suit any type T of C<T>, so compiler free to choose
(and generate) operator == as it wishes.

> It would seem that my expectations concerning what friend
> declarations resolve to were mistaken. This may be because
>
> template<class Other>
> friend bool operator == (C<int>&, C<Other>&);
>
> would represent a kind of partial specialisation.

As I wrote above, function templates don't have partial
specialization. All functions templates are primary
templates and compete equally.

I'm not sure whether is it possible to tie

template <class U, class V>
bool operator ==(C<U>&, C<V>&);

to C<T> somehow. The best you can do is to provide
specialization for each desired pair of types:

template <>
bool operator == (C<int> u, C<float> v) { ... }

template <>
bool operator == (C<int*> u, C<float> v) { ... }

etc..

HTH
Alex



Re: Class templates and friend function templates by John

John
Sun Jul 24 10:52:53 CDT 2005

"Alex Blekhman" <tkfx.N05P4M@yahoo.com> wrote in message
news:ebqBPQEkFHA.3256@TK2MSFTNGP12.phx.gbl
>
> The confusion stems from the expectation that function
> template instantiation is similar to class template
> instantiation. Actually, they're quite different. Class
> templates support partial specialization. Partially
> spesialized type of class participates in type resolution on
> par with primary template.
>
> Function template doesn't support partial specialization.

I am aware that function templates cannot be partially specialised. However,
at no point in the code I supplied is operator== specialised, either fully
or partially. The issue is the specialisation of the *friend declaration*,
not the specialisation of the operator. Friend declarations have their own
rules regarding specialisation.

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.

What is a little curious to me is that compilers will accept a friend
declaration for a function that has the appearance of allowing a partial
specialisation of the friend declaration, when in fact the friend
declaration is not specialised at all. When I try to do something analogous
with a class, it won't compile, e.g.,

#include <iostream>
using namespace std;

template<class X, class Y>
class B;

template<class T>
class A
{
template<class Other>
friend class B; //won't compile, nor will friend class B<T, Other>;
int x;
public:
A(int x_) : x(x_)
{}
};

template<class X, class Y>
class B
{
public:
template<class T>
void foo(A<T>& a)
{
cout << a.x;
}
};


int main()
{
A<int> a(7);
B<double, char> b;
b.foo(a);
}


--
John Carson



Re: Class templates and friend function templates by Alex

Alex
Sun Jul 24 15:07:03 CDT 2005

John Carson wrote:
>> Function template doesn't support partial specialization.
>
> I am aware that function templates cannot be partially
> specialised. However, at no point in the code I supplied
> is operator== specialised, either fully or partially. The
> issue is the specialisation of the *friend declaration*,
> not the specialisation of the operator. Friend
> declarations have their own rules regarding
> specialisation.
>
> 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.

Unfortunately I don't have this book at hand. However, I
looked in the standard, paragraph 14.5.3/1. There are
several examples of template friends:

template<class T> class task;
template<class T> task<T>* preempt(task<T>*);

template<class T> class task {
// ...
friend void next_time();
friend void process(task<T>*);
friend task<T>* preempt<T>(task<T>*);
template<class C> friend int func(C);
friend class task<int>;
template<class P> friend class frd;
// ...
};

---
[...] each specialization of the `task' class template has
all specializations of the function template `func' as
friends.
---

I think it's the same case as our operator ==. It's enough
that friend's template arguments are different from class'
template arguments, so compiler is free to match any
friend's specialization then.

In addition, paragraph 14.5.3/4 states:

---
A template friend declaration specifies that all
specializations of that template, whether they are
implicitly instantiated (14.7.1), partially specialized
(14.5.4) or explicitly specialized (14.7.3), are friends of
the class containing the template friend declaration.
---

So, given all that, the specialization (from original post)

bool operator == (C<int>&, C<float>&);

is a friend both of C<int> and C<float>. That answers the
question why it has an access to both instantiations if
C<T>.

> What is a little curious to me is that compilers will
> accept a friend declaration for a function that has the
> appearance of allowing a partial specialisation of the
> friend declaration, when in fact the friend declaration
> is not specialised at all. When I try to do something
> analogous with a class, it won't compile, e.g.,
>
> #include <iostream>
> using namespace std;
>
> template<class X, class Y>
> class B;
>
> template<class T>
> class A
> {
> template<class Other>
> friend class B; //won't compile, nor will friend
> //class B<T, Other>; int x;
> public:
> A(int x_) : x(x_)
> {}
> };

Actually, there is a missing template argument for B. When
you specify it, then code compiles without problems:

//...
template<class Other, class Whatever>
friend class B;

There can be T instead of Other or Whatever arguments.



Re: Class templates and friend function templates by John

John
Sun Jul 24 22:15:27 CDT 2005

Hi Alex,

I appreciate your thoughts.

"Alex Blekhman" <tkfx.N05P4M@yahoo.com> wrote in message
news:uNCnDtIkFHA.3448@TK2MSFTNGP12.phx.gbl
> 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.
>
> Unfortunately I don't have this book at hand. However, I
> looked in the standard, paragraph 14.5.3/1. There are
> several examples of template friends:
>
> template<class T> class task;
> template<class T> task<T>* preempt(task<T>*);
>
> template<class T> class task {
> // ...
> friend void next_time();
> friend void process(task<T>*);
> friend task<T>* preempt<T>(task<T>*);
> template<class C> friend int func(C);
> friend class task<int>;
> template<class P> friend class frd;
> // ...
> };
>
> ---
> [...] each specialization of the `task' class template has
> all specializations of the function template `func' as
> friends.
> ---
>
> I think it's the same case as our operator ==. It's enough
> that friend's template arguments are different from class'
> template arguments, so compiler is free to match any
> friend's specialization then.

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>&);


> In addition, paragraph 14.5.3/4 states:
>
> ---
> A template friend declaration specifies that all
> specializations of that template, whether they are
> implicitly instantiated (14.7.1), partially specialized
> (14.5.4) or explicitly specialized (14.7.3), are friends of
> the class containing the template friend declaration.
> ---
>
> So, given all that, the specialization (from original post)
>
> bool operator == (C<int>&, C<float>&);
>
> is a friend both of C<int> and C<float>. That answers the
> question why it has an access to both instantiations if
> C<T>.
>
>> What is a little curious to me is that compilers will
>> accept a friend declaration for a function that has the
>> appearance of allowing a partial specialisation of the
>> friend declaration, when in fact the friend declaration
>> is not specialised at all. When I try to do something
>> analogous with a class, it won't compile, e.g.,
>>
>> #include <iostream>
>> using namespace std;
>>
>> template<class X, class Y>
>> class B;
>>
>> template<class T>
>> class A
>> {
>> template<class Other>
>> friend class B; //won't compile
>> int x;
>> public:
>> A(int x_) : x(x_)
>> {}
>> };
>
> Actually, there is a missing template argument for B.

I know there is, but it was also missing in the operator== friend
declaration and that still compiled. See above.

> When you specify it, then code compiles without problems:
>
> //...
> template<class Other, class Whatever>
> friend class B;
>
> There can be T instead of Other or Whatever arguments.

VC++ lets you use T, but Comeau won't let you re-use the template parameter
from the enclosing class. Comeau's behaviour makes more sense since it makes
it clear that the friendship rights do not require that classes A and
B share a template argument.

--
John Carson


Re: Class templates and friend function templates by Tom

Tom
Mon Jul 25 05:28:18 CDT 2005

Carl Daniel [VC++ MVP] wrote:
> Carl Daniel [VC++ MVP] wrote:
>
>
>>template <class U,class V>
>>friend bool operator == <T>(U u, V v);
>
>
> should be:
>
> template <class U,class V>
> friend bool operator == <T>(C<U> u, C<V> v);
>
> Oddly, VC++ likes it either way, Comeau likes neither. More than likely
> it's a VC bug that this code compiles (and appears to behave as desired).

It's simpler than that:

template <class T> class C
{
public: C(int x_) : x(x_) {}

private: int x;

template <class U, class V>
friend bool operator ==(C<U> u, C<V> v);
};

template <class U, class V>
bool operator == (C<U> u, C<V> v)
{
return u.x == v.x;
}

int main()
{
C<int> c1(1);
C<float> c2(2);
bool b = c1 == c2;
}

No need to predeclare the template if you just grant friendship to all
specializations (which I realise is a slightly greater granularity than
wanted, but it is harmless).

Tom

Re: Class templates and friend function templates by Alex

Alex
Mon Jul 25 11:24:16 CDT 2005

John Carson wrote:
> [...] 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>&);

After twiddling with it for some time I discovered that some
kind of tie between enclosing class and operator == can be
achieved. If I provide friend specialization that matches
enclosing class' instantiation type (`int' for this sample):

template <class V>
bool operator == (C<int>& u, C<V> &v) { ... }

then operator == ceases to be a friend of C<float>. Compiler
emits C2248 (cannot access private member of C<float>).
However, if I declare friend template with both template
types:

template <class T, class Other>
friend bool operator == (C<T>&, C<Other>&);

then T becomes just any type, not the type of enclosed
class, as you pointed already.

I think we're touching here some dark corner of the
language.



Re: Class templates and friend function templates by John

John
Mon Jul 25 17:33:05 CDT 2005

"Alex Blekhman" <tkfx.N05P4M@yahoo.com> wrote in message
news:%23GkNPVTkFHA.3288@TK2MSFTNGP10.phx.gbl
>
> After twiddling with it for some time I discovered that some
> kind of tie between enclosing class and operator == can be
> achieved. If I provide friend specialization that matches
> enclosing class' instantiation type (`int' for this sample):
>
> template <class V>
> bool operator == (C<int>& u, C<V> &v) { ... }
>
> then operator == ceases to be a friend of C<float>. Compiler
> emits C2248 (cannot access private member of C<float>).
> However, if I declare friend template with both template
> types:
>
> template <class T, class Other>
> friend bool operator == (C<T>&, C<Other>&);
>
> then T becomes just any type, not the type of enclosed
> class, as you pointed already.
>
> I think we're touching here some dark corner of the
> language.


Very dark indeed :-)

--
John Carson

Re: Class templates and friend function templates by google

google
Tue Jul 26 09:24:06 CDT 2005



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


Re: Class templates and friend function templates by John

John
Tue Jul 26 13:42:53 CDT 2005

<google@vandevoorde.com> wrote in message
news:1122387846.598308.230620@o13g2000cwo.googlegroups.com
> John Carson wrote:
>
> [...]
>> 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


Thanks for those remarks. I really appreciate you taking the time to
comment.

It never occurred to me that the friend declaration could be an overload.
That certainly helps make sense of why the code compiles. I still have some
questions, however. The following code compiles on both VC++ 8.0 (Beta 2)
and Comeau Online.

#include <iostream>
using namespace std;

template <class T>
class C
{
public:
C(int x_) : x(x_) {}
private:
int x;

template <class Other>
friend bool operator == (C<T>&, C<Other>&);
};

// global instance of C<int*>
C<int*> c0(7);

template <class U, class V>
bool operator == (C<U>& u, C<V> &v)
{
// access private data of c0
cout << c0.x;

return u.x == v.x;
}

int main()
{
C<int> c1(1);
C<float> c2(2);
bool b = c1 == c2;
return 0;
}

My questions concerning that code are:

1. If the friend declaration declares an overload, where is that overload
defined? (Comeau Online says it doesn't link, but "will instantiate all
templates hence doing a fake link" --- I am not sure exactly what that means
and whether it is relevant, but VC++ certainly links).

2. If I have understood you correctly, the definitions of c0, c1 and c2
should lead to the following overload friend declarations:

template <class Other>
friend bool operator == (C<int*>&, C<Other>&);

template <class Other>
friend bool operator == (C<int>&, C<Other>&);

template <class Other>
friend bool operator == (C<float>&, C<Other>&);

respectively. The line from main()

bool b = c1 == c2;

should lead to a call to

operator == (C<int>&, C<float>&);

I can't see where the friend declarations make this operator a friend of
C<int*>, yet it can access the private data of c0, which is an instance of
C<int*>. (For that matter, I can't see where the friend declarations make
the operator a friend of C<float>.)


--
John Carson


Re: Class templates and friend function templates by google

google
Tue Jul 26 20:57:02 CDT 2005



John Carson wrote:
[...]
> Thanks for those remarks. I really appreciate you taking the time to
> comment.
>
> It never occurred to me that the friend declaration could be an overload.
> That certainly helps make sense of why the code compiles. I still have some
> questions, however. The following code compiles on both VC++ 8.0 (Beta 2)
> and Comeau Online.
>
> #include <iostream>
> using namespace std;
>
> template <class T>
> class C
> {
> public:
> C(int x_) : x(x_) {}
> private:
> int x;
>
> template <class Other>
> friend bool operator == (C<T>&, C<Other>&);
> };
>
> // global instance of C<int*>
> C<int*> c0(7);
>
> template <class U, class V>
> bool operator == (C<U>& u, C<V> &v)
> {
> // access private data of c0
> cout << c0.x;
>
> return u.x == v.x;
> }
>
> int main()
> {
> C<int> c1(1);
> C<float> c2(2);
> bool b = c1 == c2;
> return 0;
> }
>
> My questions concerning that code are:
>
> 1. If the friend declaration declares an overload, where is that overload
> defined?

In your example it is not defined. However, you can defined it
"inline" (i.e., as part of the friend declaration).

> (Comeau Online says it doesn't link, but "will instantiate all
> templates hence doing a fake link" --- I am not sure exactly what that means
> and whether it is relevant, but VC++ certainly links).

I suspect the online version uses an EDG option to "instantiate
every used template instance". However, it is not an actual link
operation.

Our demo compiler in its strict mode leads to the following
link error:

bool operator ==<T1>(C<int> &, C<T1> &) [with T1=float] t.o
ld: fatal: Symbol referencing errors. No output written to a.out

which is as expected.

> 2. If I have understood you correctly, the definitions of c0, c1 and c2
> should lead to the following overload friend declarations:
>
> template <class Other>
> friend bool operator == (C<int*>&, C<Other>&);
>
> template <class Other>
> friend bool operator == (C<int>&, C<Other>&);
>
> template <class Other>
> friend bool operator == (C<float>&, C<Other>&);
>
> respectively.

Correct.

> The line from main()
>
> bool b = c1 == c2;
>
> should lead to a call to
>
> operator == (C<int>&, C<float>&);

The signature you quote there isn't detailed enough.
The candidates are the three friend functions you
mention above and the template defined in your
example. Of those, the viable ones (i.e., the ones
that could resolve the "c1 == c2" expression) are

template<class Other> friend
bool operator==(C<int>&, C<Other>&);

and

template<class U, class V>
bool operator== (C<U>&, C<V>&);

The deduced signatures of these two are equally good
(they're in fact the same types). Therefore, the concept of
"partial ordering of function templates" (section 14.5.5.2
in the standard) comes into play. In this case, the first
declaration (the friend) is selected and since it doesn't
have a definition, you get the linker error mentioned
above.

(You can tell the partial ordering by noticing that the
friend candidate "could be an instance" of the nonfriend
candidate, but not vice versa -- I'm talking function
types here.)

> I can't see where the friend declarations make this operator a friend of
> C<int*>, yet it can access the private data of c0, which is an instance of
> C<int*>. (For that matter, I can't see where the friend declarations make
> the operator a friend of C<float>.)

Note that the nonfriend template is never instantiated
and the access check (or error) is therefore never needed.

Daveed


Re: Class templates and friend function templates by John

John
Wed Jul 27 00:35:56 CDT 2005

<google@vandevoorde.com> wrote in message
news:1122429421.968377.141230@g43g2000cwa.googlegroups.com
> John Carson wrote:
> [...]
>> Thanks for those remarks. I really appreciate you taking the time to
>> comment.
>>
>> It never occurred to me that the friend declaration could be an
>> overload. That certainly helps make sense of why the code compiles.
>> I still have some questions, however. The following code compiles on
>> both VC++ 8.0 (Beta 2) and Comeau Online.
>>
>> #include <iostream>
>> using namespace std;
>>
>> template <class T>
>> class C
>> {
>> public:
>> C(int x_) : x(x_) {}
>> private:
>> int x;
>>
>> template <class Other>
>> friend bool operator == (C<T>&, C<Other>&);
>> };
>>
>> // global instance of C<int*>
>> C<int*> c0(7);
>>
>> template <class U, class V>
>> bool operator == (C<U>& u, C<V> &v)
>> {
>> // access private data of c0
>> cout << c0.x;
>>
>> return u.x == v.x;
>> }
>>
>> int main()
>> {
>> C<int> c1(1);
>> C<float> c2(2);
>> bool b = c1 == c2;
>> return 0;
>> }
>>
>> My questions concerning that code are:
>>
>> 1. If the friend declaration declares an overload, where is that
>> overload defined?
>
> In your example it is not defined. However, you can defined it
> "inline" (i.e., as part of the friend declaration).
>
>> (Comeau Online says it doesn't link, but "will instantiate all
>> templates hence doing a fake link" --- I am not sure exactly what
>> that means and whether it is relevant, but VC++ certainly links).
>
> I suspect the online version uses an EDG option to "instantiate
> every used template instance". However, it is not an actual link
> operation.
>
> Our demo compiler in its strict mode leads to the following
> link error:
>
> bool operator ==<T1>(C<int> &, C<T1> &) [with T1=float] t.o
> ld: fatal: Symbol referencing errors. No output written to a.out
>
> which is as expected.


Yes, that is what I would have expected based on your comments. VC++,
however, doesn't give any errors, compiler or linker, and the code runs and
outputs the value 7 (the x value from c0). This would appear to be a bug in
VC++. If one can make any sense of the VC++ behaviour, it seems to be
accepting

template <class Other>
friend bool operator == (C<T>&, C<Other>&);

on the basis that it is injecting a new entity but then accepting

template <class U, class V>
bool operator == (C<U>& u, C<V> &v)
{
cout << c0.x;
return u.x == v.x;
}

as the source of this new entity's definition.

As for Comeau, I have used the online version for a long time as a test of
correctness, but clearly I need the full version (with actual linking) if I
am to test some of the subtler template issues.

>> 2. If I have understood you correctly, the definitions of c0, c1 and
>> c2 should lead to the following overload friend declarations:
>>
>> template <class Other>
>> friend bool operator == (C<int*>&, C<Other>&);
>>
>> template <class Other>
>> friend bool operator == (C<int>&, C<Other>&);
>>
>> template <class Other>
>> friend bool operator == (C<float>&, C<Other>&);
>>
>> respectively.
>
> Correct.
>
>> The line from main()
>>
>> bool b = c1 == c2;
>>
>> should lead to a call to
>>
>> operator == (C<int>&, C<float>&);
>
> The signature you quote there isn't detailed enough.
> The candidates are the three friend functions you
> mention above and the template defined in your
> example. Of those, the viable ones (i.e., the ones
> that could resolve the "c1 == c2" expression) are
>
> template<class Other> friend
> bool operator==(C<int>&, C<Other>&);
>
> and
>
> template<class U, class V>
> bool operator== (C<U>&, C<V>&);
>
> The deduced signatures of these two are equally good
> (they're in fact the same types). Therefore, the concept of
> "partial ordering of function templates" (section 14.5.5.2
> in the standard) comes into play. In this case, the first
> declaration (the friend) is selected and since it doesn't
> have a definition, you get the linker error mentioned
> above.
>
> (You can tell the partial ordering by noticing that the
> friend candidate "could be an instance" of the nonfriend
> candidate, but not vice versa -- I'm talking function
> types here.)
>
>> I can't see where the friend declarations make this operator a
>> friend of C<int*>, yet it can access the private data of c0, which
>> is an instance of C<int*>. (For that matter, I can't see where the
>> friend declarations make the operator a friend of C<float>.)
>
> Note that the nonfriend template is never instantiated
> and the access check (or error) is therefore never needed.
>
> Daveed

OK. That explains why Comeau online doesn't flag an access error.

VC++, on the other hand, is doing at least two things wrong:

1. It is instantiating an instance of the operator from

template <class U, class V>
bool operator == (C<U>& u, C<V> &v)
{
cout << c0.x;
return u.x == v.x;
}

when it should instead be producing a link error for the more specialised
form of the operator declared in the friend declaration.

2. It is granting this operator friendship rights that it shouldn't have.

Again, many thanks for your comments.


--
John Carson


Re: Class templates and friend function templates by google

google
Wed Jul 27 08:33:12 CDT 2005



John Carson wrote:
[...]
> VC++, on the other hand, is doing at least two things wrong:

Our (EDG) compiler has a "Microsoft bugs" mode that also
emulates this. I looked it up in our documentation...

> 1. It is instantiating an instance of the operator from
>
> template <class U, class V>
> bool operator == (C<U>& u, C<V> &v)
> {
> cout << c0.x;
> return u.x == v.x;
> }
>
> when it should instead be producing a link error for the more specialised
> form of the operator declared in the friend declaration.
>
> 2. It is granting this operator friendship rights that it shouldn't have.

While this is true, they are both the consequence of the same bug:
Microsoft compilers seem to treat friend function declarations as
what used to be known as "guiding function declarations". (I meant
to write about those in the "C++ Templates" book, but it somehow
never made it into the text.) A "guiding function declaration" was a
declaration of an instance of a template. It was different from an
explicit specialization in that it did not inhibit the instance from
being generated. (The ARM hints at the existence of guiding
functions and for a while they were formally specified in the
Working Paper that eventually became the C++ standard. They were
removed from the standard when the notion of "signature" was
finalized, if I remember correctly.)

So what's happening in the example is that the friend declaration
injected by MSVC++ is _not_ equivalent to

template<typename Other>
bool operator==(C<int>&, C<Other>&);

but to some other construct that can no longer be expressed in
standard C++ (and in fact, I don't think the parameterized form
was ever possible). For argument's sake:

__guide template<typename Other>
bool operator==(C<int>&, C<Other>&);

This "guiding declaration" gets matched to a template declaration
that _follows_ it (a rather funny concept for C++, IMO). The final
result is that a subset of instances is made a friend of the class,
which is in fact what the original poster wanted. You can verify
this by replacing "C<Other>" in the friend declaration by "C<Other*>":
I think that will result in access errors.

(Note that this analysis is based on observation alone. The MSVC++
compiler may very well work completely differently internally.)

As you can imagine, figuring out that kind of stuff and emulating
the associated bugs in an otherwise standard compiler is loads of
fun ;-)

Daveed


Re: Class templates and friend function templates by John

John
Wed Jul 27 11:09:59 CDT 2005

<google@vandevoorde.com> wrote in message
news:1122471192.878354.184640@z14g2000cwz.googlegroups.com
> John Carson wrote:
> [...]
>> VC++, on the other hand, is doing at least two things wrong:
>
> Our (EDG) compiler has a "Microsoft bugs" mode that also
> emulates this. I looked it up in our documentation...
>
>> 1. It is instantiating an instance of the operator from
>>
>> template <class U, class V>
>> bool operator == (C<U>& u, C<V> &v)
>> {
>> cout << c0.x;
>> return u.x == v.x;
>> }
>>
>> when it should instead be producing a link error for the more
>> specialised form of the operator declared in the friend declaration.
>>
>> 2. It is granting this operator friendship rights that it shouldn't
>> have.
>
> While this is true, they are both the consequence of the same bug:
> Microsoft compilers seem to treat friend function declarations as
> what used to be known as "guiding function declarations". (I meant
> to write about those in the "C++ Templates" book, but it somehow
> never made it into the text.) A "guiding function declaration" was a
> declaration of an instance of a template. It was different from an
> explicit specialization in that it did not inhibit the instance from
> being generated.

You mean being generated from the general template.

> (The ARM hints at the existence of guiding
> functions and for a while they were formally specified in the
> Working Paper that eventually became the C++ standard. They were
> removed from the standard when the notion of "signature" was
> finalized, if I remember correctly.)
>
> So what's happening in the example is that the friend declaration
> injected by MSVC++ is _not_ equivalent to
>
> template<typename Other>
> bool operator==(C<int>&, C<Other>&);
>
> but to some other construct that can no longer be expressed in
> standard C++ (and in fact, I don't think the parameterized form
> was ever possible). For argument's sake:
>
> __guide template<typename Other>
> bool operator==(C<int>&, C<Other>&);
>
> This "guiding declaration" gets matched to a template declaration
> that _follows_ it (a rather funny concept for C++, IMO). The final
> result is that a subset of instances is made a friend of the class,
> which is in fact what the original poster wanted. You can verify
> this by replacing "C<Other>" in the friend declaration by "C<Other*>":
> I think that will result in access errors.

Nope. Replacing C<Other> with C<Other*> makes no difference. Friendship
seems to be granted without restriction to every instantiation of the
operator. This is true of both VC++ 7.1 and VC++ 8.0 Beta 2. This suggests
to me that there is more than one bug involved though, as you indicate
below, the mechanism underlying observed behaviour is difficult to infer.

> (Note that this analysis is based on observation alone. The MSVC++
> compiler may very well work completely differently internally.)
>
> As you can imagine, figuring out that kind of stuff and emulating
> the associated bugs in an otherwise standard compiler is loads of
> fun ;-)
>
> Daveed


--
John Carson


Re: Class templates and friend function templates by google

google
Wed Jul 27 15:02:22 CDT 2005



John Carson wrote:
[...]
> > You can verify
> > this by replacing "C<Other>" in the friend declaration by "C<Other*>":
> > I think that will result in access errors.
>
> Nope. Replacing C<Other> with C<Other*> makes no difference. Friendship
> seems to be granted without restriction to every instantiation of the
> operator. This is true of both VC++ 7.1 and VC++ 8.0 Beta 2. This suggests
> to me that there is more than one bug involved though, as you indicate
> below, the mechanism underlying observed behaviour is difficult to infer.

Weird. The behavior changed from version 7.0 to 7.1 (though
our emulation isn't exact for either version). The friend declaration
does matter though.

For 7.1 apparently _any_ reference to an instance of C will do.
Replace C<Other> by C<void> and the code is still accepted.
Replace it by C<Other>* and you get an access error.

You're right: There is some other (really strange) bug at work
here.

Daveed