Re: Class templates and friend function templates



<google@xxxxxxxxxxxxxxx> wrote in message
news:1122429421.968377.141230@xxxxxxxxxxxxxxxxxxxxxxxxxxxx
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


.



Relevant Pages

  • Re: Class templates and friend function templates
    ... friend void process; ... each specialization of the `task' class template has all specializations of the function template `func' as friends. ... 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. ...
    (microsoft.public.vc.language)
  • Re: Class templates and friend function templates
    ... > It never occurred to me that the friend declaration could be an overload. ... > template ... I suspect the online version uses an EDG option to "instantiate ...
    (microsoft.public.vc.language)
  • Re: C2783 in VS 6.0 but not in VS.NET 2003
    ... > The problem is with the GetPtr function and friend declaration. ... I don't have to have separate libraries for it? ...
    (microsoft.public.vc.language)
  • Re: IO-Operator overloading question
    ... >>invoke a virtual member function, ... > And we have no need to involve a friend declaration. ... It CAN be written without a friend, by making the virtual I/O function ...
    (alt.comp.lang.learn.c-cpp)
  • Re: Templats and I/O operators (<< >>)
    ... > In my Draft copy of the standard: ... > A friend function defined in a class is in the ...
    (alt.comp.lang.learn.c-cpp)