Topic: template friends


Author: cpdaniel_remove_this_and_nospam@mvps.org.nospam ("Carl Daniel")
Date: Sat, 13 Dec 2003 03:16:18 +0000 (UTC)
Raw View
Consider the following code:

// <code>
template <class T> class C;

template <class T1, class T2> T1 f(const C<T2>&); // 1
template <class T> T f(const C<T>&); // 2

template <class T> class C
{
  private:  T m_t;

  friend T f<T,T>(const C&); // a
  friend T f<T>(const C&);   // b
  friend T f<>(const C&);    // c
};

template <class T>
T f(const C<T>& ct)
{
  return ct.m_t;
}

template <class T1, class T2>
T1 f(const C<T2>& ct)
{
  return ct.m_t;
}

void test()
{
   C<int> ci;
   f<int>(ci);
   f<int,int>(ci);
}

// </code>

According to Comeau online, any of the three friend declarations (a/b/c)
grants friendship to both template functions (1/2).

I would intuitively expect that 'a' should grant friendship to '1', 'b'
should grant friendship to '2' and 'c' should grant friendship to both '1'
and '2'.

Is Comeau right?  (It usually is!)

-cd

---
[ 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: rani_sharoni@hotmail.com ("Rani Sharoni")
Date: Mon, 15 Dec 2003 09:43:13 +0000 (UTC)
Raw View
"Carl Daniel" wrote:
> Consider the following code:
>
> // <code>
> template <class T> class C;
>
> template <class T1, class T2> T1 f(const C<T2>&); // 1
> template <class T> T f(const C<T>&); // 2
> [...]
> // </code>
>
> [...]
> Is Comeau right?  (It usually is!)

// My previous response was lost but maybe this time it will find its way.

AFAICT friends are not the issue here.
The problems that you encountered boils down to the question whether the
following code contains ambiguity:

template<typename T> struct A { A(int = 0); };

template<typename T1, typename T2> // #1
T1 f(const A<T2>&) { return T1(); }

template<typename T1>  // #2
T1 f(const A<T1>&)
{
    typedef typename T1::force_error type;
    return T1();
}

int x1 = f<int>(A<int>());

There are two non-ordered specializations candidates:
int f<int, int>(const A<int>&); // from #1
int f<int>(const A<int>&);       // from #2

Both candidates generates the *same* type and therefore it seems that the
code contains an ambiguity. EDG and GCC found the code well-formed which
proves that #1 was selected. VC found an ambiguity.

There is subtle different between the two candidates since #2 contain
non-deduced context (i.e. the template argument was explicitly specified). I
replaced #2 argument with true non-deduced argument (i.e. identity template
below) and all compilers agreed that the code is ambiguous which shows that
EDG and GCC are a bit inconsistent.

Anyway, In case that EDG and GCC are right then here is an interesting
technique that allows conversions when calling function template which might
be useful for user defined operators (i.e. operator+(complex, complex)):

template<typename T> struct identity { typedef T type; };

template<typename T>
char* g(const A<T>&, const A<T>&)
{ return 0; }

template<typename T>
long* g(const A<T>&, typename identity<const A<T>&>::type)
{ return 0; }

template<typename T>
int*  g(typename identity<const A<T>&>::type, const A<T>&)
{ return 0; }

A<int> a(10);

char* x2 = g(a, a);
long* x3 = g(a, 10); // allow conversion
int*  x4 = g(10, a); // allow conversion

EDG and GCC compiled the code while VC found an ambiguity.

Rani



---
[ 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: cpdaniel_remove_this_and_nospam@mvps.org.nospam ("Carl Daniel")
Date: Mon, 15 Dec 2003 16:45:23 +0000 (UTC)
Raw View
"Rani Sharoni" wrote:
> "Carl Daniel" wrote:
>> Consider the following code:
>>
>> // <code>
>> template <class T> class C;
>>
>> template <class T1, class T2> T1 f(const C<T2>&); // 1
>> template <class T> T f(const C<T>&); // 2
>> [...]
>> // </code>
>>
>> [...]
>> Is Comeau right?  (It usually is!)
>
> // My previous response was lost but maybe this time it will find its
> way.
>
> AFAICT friends are not the issue here.
> The problems that you encountered boils down to the question whether
> the following code contains ambiguity:

d'oh!  Yes, of course.

This wasn't really a problem in real code, but a test-case intended to
answer a specific question.  A test case which I constructed with
insufficient care.  The question I was intending to explore was the exactl
meaning of the friend declaration with no template arguments specified.

The very interesting question that you spotted in the results of my botched
experiment is another matter entirely.

-cd




---
[ 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: deepblue57x@yahoo.co.nz (Graeme Prentice)
Date: Mon, 15 Dec 2003 20:24:26 +0000 (UTC)
Raw View
On Sat, 13 Dec 2003 03:16:18 +0000 (UTC),
cpdaniel_remove_this_and_nospam@mvps.org.nospam ("Carl Daniel") wrote:

>Consider the following code:
>
>// <code>
>template <class T> class C;
>
>template <class T1, class T2> T1 f(const C<T2>&); // 1
>template <class T> T f(const C<T>&); // 2
>
>template <class T> class C
>{
>  private:  T m_t;
>
>  friend T f<T,T>(const C&); // a
>  friend T f<T>(const C&);   // b
>  friend T f<>(const C&);    // c
>};
>
>template <class T>
>T f(const C<T>& ct)
>{
>  return ct.m_t;
>}
>
>template <class T1, class T2>
>T1 f(const C<T2>& ct)
>{
>  return ct.m_t;
>}
>
>void test()
>{
>   C<int> ci;
>   f<int>(ci);
>   f<int,int>(ci);
>}
>
>// </code>
>
>According to Comeau online, any of the three friend declarations (a/b/c)
>grants friendship to both template functions (1/2).
>
>I would intuitively expect that 'a' should grant friendship to '1', 'b'
>should grant friendship to '2' and 'c' should grant friendship to both '1'
>and '2'.
>
>Is Comeau right?  (It usually is!)

yep, except that both function calls to f() from test() call the version
of f() that has two template parameters, just as all 3 friend
declarations refer to the two template parameter version of f().

(If you purchased the Comeau compiler (it's cheap) you could execute the
code to see this).

14.8.1 para 2 allows trailing template arguments to be omitted,
including in a friend declaration.  Partial ordering finds the two
template parameter f() to be more specialised because decuction from it
into the one-template-parameter f() succeeds but fails in reverse
because the return type T1 can't be deduced.

Defect report 214 proposes to alter partial ordering to allow for some
return type cases  - it says that for partial ordering purposes, a
template parameter may remain without a "value" if it is not used in the
types being used for partial ordering.  In your example, the return type
T1 is not used in the types being used for partial ordering so according
to defect report 214, the function calls and friend declarations are
ambiguous  - just like VC7.1 says :-)  - I guess VC7.1 is ahead of the
times.

Here's the example from the defect report that shows how the template
parameter that appears only in the return type is ignored

template <class T> T f(int);        // #1
template <class T, class U> T f(U); // #2
void g() {
    f<int>(1);  // Calls #1
}

The intention is that the int function can be favoured by partial
ordering because it is "obviously" more specialised even though
deduction fails in both directions because the return type can't be
deduced.

I have a feeling it will be a while before defect report 214 becomes
part of the standard.  I asked some questions on here a while ago about
how it proposes to drop references and CV qualifiers during partial
ordering but no-one responded.

Graeme

---
[ 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: deepblue57x@yahoo.co.nz (Graeme Prentice)
Date: Tue, 16 Dec 2003 03:37:08 +0000 (UTC)
Raw View
On Sat, 13 Dec 2003 03:16:18 +0000 (UTC),
cpdaniel_remove_this_and_nospam@mvps.org.nospam ("Carl Daniel") wrote:

>Consider the following code:
>
>// <code>
>template <class T> class C;
>
>template <class T1, class T2> T1 f(const C<T2>&); // 1
>template <class T> T f(const C<T>&); // 2
>
>template <class T> class C
>{
>  private:  T m_t;
>
>  friend T f<T,T>(const C&); // a
>  friend T f<T>(const C&);   // b
>  friend T f<>(const C&);    // c
>};
>
>template <class T>
>T f(const C<T>& ct)
>{
>  return ct.m_t;
>}
>
>template <class T1, class T2>
>T1 f(const C<T2>& ct)
>{
>  return ct.m_t;
>}
>
>void test()
>{
>   C<int> ci;
>   f<int>(ci);
>   f<int,int>(ci);
>}
>
>// </code>
>
>According to Comeau online, any of the three friend declarations (a/b/c)
>grants friendship to both template functions (1/2).
>
>I would intuitively expect that 'a' should grant friendship to '1', 'b'
>should grant friendship to '2' and 'c' should grant friendship to both '1'
>and '2'.
>
>Is Comeau right?  (It usually is!)


yep, except that both function calls to f() from test() call the version
of f() that has two template parameters, just as all 3 friend
declarations refer to the two template parameter version of f().

(If you purchased the Comeau compiler (it's cheap) you could execute the
code to see this).

14.8.1 para 2 allows trailing template arguments to be omitted,
including in a friend declaration.  Partial ordering finds the two
template parameter f() to be more specialised because decuction from it
into the one-template-parameter f() succeeds but fails in reverse
because the return type T1 can't be deduced.

Defect report 214 proposes to alter partial ordering to allow for some
return type cases  - it says that for partial ordering purposes, a
template parameter may remain without a "value" if it is not used in the
types being used for partial ordering.  In your example, the return type
T1 is not used in the types being used for partial ordering so according
to defect report 214, the function calls and friend declarations are
ambiguous  - just like VC7.1 says :-)  - I guess VC7.1 is ahead of the
times.

Here's the example from the defect report that shows how the template
parameter that appears only in the return type is ignored

template <class T> T f(int);        // #1
template <class T, class U> T f(U); // #2
void g() {
    f<int>(1);  // Calls #1
}

The intention is that the int function can be favoured by partial
ordering because it is "obviously" more specialised even though
deduction fails in both directions because the return type can't be
deduced.

I have a feeling it will be a while before defect report 214 becomes
part of the standard.  I asked some questions on here a while ago about
how it proposes to drop references and CV qualifiers during partial
ordering but no-one responded.

Graeme

---
[ 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: "Ben Jones" <ben_j@usa.net>
Date: 1999/03/15
Raw View
Is it possible to declare all instances of a template class as friends of
another class? For example,

template <class T>
class TemplateClass
{
};

class NormalClass
{
  friend TemplateClass;
};

This doesn't work. Is there another syntax? (I'm using Visual C++ and
Metrowerks Codewarrior 3 for embedded PPC if it makes a difference).

Thanks in advance
Ben Jones
ben_j@usa.net
(sorry if this is a duplicate post -- problems using this newsreader for the
first time)

[ moderator's note: Please follow the procedures in the FAQ if you
  are not sure whether your post was received. -sdc ]



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/03/15
Raw View
On 15 Mar 1999 17:16:41 GMT, Ben Jones <ben_j@usa.net> wrote:

>template <class T>
>class TemplateClass
>{
>};
>
>class NormalClass
>{
>  friend TemplateClass;
>};

   template <class T> friend TemplateClass<T>;

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Ben Jones" <ben_j@usa.net>
Date: 1999/03/18
Raw View
Thanks for your suggestion Siemel...

>   template <class T> friend TemplateClass<T>;

I tried this, but with visual C++ I get:
error C2059: syntax error : '<end Parse>'
error C2143: syntax error : missing ';' before '}'
error C2238: unexpected token(s) preceding ';'

Does it work for you? -- in which case, what compiler are you using? Is it
part of the standard?

Thanks,
ben_j@usa.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]