Topic: template friend
Author: jpotter@falcon.lhup.edu (John Potter)
Date: Sun, 28 Apr 2002 12:50:12 GMT Raw View
This seems like a simple problem. Compilers do not seem to agree.
template <class T>
class C {
template <class U>
friend C<U>& operator+= (C<U>&, C const&);
private :
T data;
};
template <class T, class U>
C<T>& operator+= (C<T>& lhs, C<U> const& rhs) {
// C<int> t;
lhs.data += rhs.data; // + t.data;
return lhs;
}
int main(int argc, char * argv[]) {
C<float> fmc;
C<double> dmc;
dmc += dmc;
dmc += fmc;
}
It would seem that the friend declaration makes any operator+= with
any lhs and this rhs a friend. Does it also make it a friend of
the lhs class?
G++ accepts it but does not instantiate the functions giving link
errors. How do you tell it that it is also templated on the second
parameter? Comeau accepts it, but also accepts it when the int
parts are included.
G++ will accept
template <class U, class V>
friend C<U>& operator+= (C<U>&, C<V> const&);
but that also makes it a friend of C<int> obviously.
It is simple to make the one type function a friend.
friend C& operator+=<> (C&, C const&);
But, once you say template, the <> becomes ill-formed.
So, how do you make a global template function a friend of this class
for either of the parameters without including all other classes?
Given that, how do you move the operator+= into the class and
accomplish the same thing. All of my attempts on this have failed
with ICE or errors or accepting anything.
It really is simple, isn't it. :)
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dmeyer@dmeyer.net ()
Date: Mon, 29 Apr 2002 11:30:23 GMT Raw View
According to John Potter <jpotter@penguin.lhup.edu>:
> This seems like a simple problem. Compilers do not seem to agree.
<snip>
>
> It would seem that the friend declaration makes any operator+= with
> any lhs and this rhs a friend. Does it also make it a friend of
> the lhs class?
Congratulations - you've just run into one of the quirkiest parts of
the whole language, IMHO.
The problem is that you're declaring operator+=<U>(...) to be a friend
of C<T>, but what you really need is for operator+=<U,T> to be a
friend of C<T>. If you compile your code (with gcc-3.0.4) with -c and
look at the nm -C output:
U C<double>& operator+=<double>(C<double>&, C<double> const&)
U C<double>& operator+=<float>(C<double>&, C<float> const&)
This is a problem, because it's not what you're implementing in your
code. Changing the friend declaration to
template <class U,class V> friend C<U>& operator+=(C<U>&, C<V> const&);
will fix your problem, I think. At least, it worked for my with gcc.
The nm -C output from that looks like:
W C<double>& operator+=<double, double>(C<double>&, C<double> const&)
W C<double>& operator+=<double, float>(C<double>&, C<float> const&)
which is much more likely to do what you want.
Dan Saks had a very good presentation on this sort of thing at the
first C++ Seminar (http://www.gotw.ca/cpp_seminar/01/index.htm) called
"Making New Friends". It's worth trying to track down a copy of the
presentation or articles by him on this topic. Sorry I don't have a
url handy.
--
Dave Meyer
dmeyer@dmeyer.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Anthony Williams"<anthwil@nortelnetworks.com>
Date: Mon, 29 Apr 2002 11:32:08 GMT Raw View
"John Potter" <jpotter@falcon.lhup.edu> wrote in message
news:3ccb7400.6572288@news.earthlink.net...
> This seems like a simple problem. Compilers do not seem to agree.
>
> template <class T>
> class C {
> template <class U>
> friend C<U>& operator+= (C<U>&, C const&);
> private :
> T data;
> };
> template <class T, class U>
> C<T>& operator+= (C<T>& lhs, C<U> const& rhs) {
> // C<int> t;
> lhs.data += rhs.data; // + t.data;
> return lhs;
> }
> int main(int argc, char * argv[]) {
> C<float> fmc;
> C<double> dmc;
> dmc += dmc;
> dmc += fmc;
> }
>
> It would seem that the friend declaration makes any operator+= with
> any lhs and this rhs a friend. Does it also make it a friend of
> the lhs class?
The friend declaration in C<T> declares a function
template<typename U>
C<U>& operator+=(C<U>&,C<T> const&);
for each T. Therefore to define it at namespace scope, you have to define it
for each and every T you wish to use for C<T> on the rhs. Each function can
then only access the members of the lh operand if U==T, as it is not a
friend of C<U> (in general)
> G++ accepts it but does not instantiate the functions giving link
> errors.
The friend declaration does not relate to the global template, so that is
unsurprising.
> How do you tell it that it is also templated on the second
> parameter? Comeau accepts it, but also accepts it when the int
> parts are included.
>
> G++ will accept
> template <class U, class V>
> friend C<U>& operator+= (C<U>&, C<V> const&);
> but that also makes it a friend of C<int> obviously.
Which it needs to be if C<int> is the lh operand, and C<MyClass> is the rh
operand. This is the correct syntax for making the global template function
a friend.
> It is simple to make the one type function a friend.
> friend C& operator+=<> (C&, C const&);
> But, once you say template, the <> becomes ill-formed.
>
> So, how do you make a global template function a friend of this class
> for either of the parameters without including all other classes?
So for T==MyClass, and U==anything you want
operator+=<MyClass,U>
operator+=<U,MyClass>
and
operator+=<MyClass,MyClass>
to be friends of C<MyClass>, but no instantiations. I can't think of a way
to do this, other than to write them out explicitly, in the class
definition, except that then they won't relate to each other, so
operator+=(C<MyClass>&,C<U> const&> won't relate to
operator+=(C<U>&,C<SomeOtherClass> const&), and will only be able to access
either the lhs or rhs private members.
> Given that, how do you move the operator+= into the class and
> accomplish the same thing. All of my attempts on this have failed
> with ICE or errors or accepting anything.
I can't see how you can. It's an extension of the following:
template<typename T>
class X
{
friend void f(X<T>&)
{
// some impl
}
};
There is no way of writing f outside the class definition. Since in your
case, f is operator+=, and needs to take parameters which are _different_
instantiations of the enclosing class template, there is no way to write it
at all. In either case, you can make a templated free function a friend, but
then every instantiation of the function is friends with every instantiation
of the class template.
Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optical Components Ltd
The opinions expressed in this message are not necessarily those of my
employer
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]