Topic: template friend function of a template class


Author: pdimov@mmltd.net (Peter Dimov)
Date: Fri, 8 Jun 2001 20:05:47 GMT
Raw View
"Andrei Iltchenko" <iltchenko@yahoo.com> wrote in message news:<9fom02$5b97a$1@ID-62495.news.dfncis.de>...
> "Peter Dimov" <pdimov@mmltd.net> wrote in message
> news:7dc3b1ea.0106070602.2a21f0d5@posting.google.com...

[...]

[Original example]

> template <typename T, unsigned Mask> class qualified {
>   public:
>    // ...
>     template <unsigned Mask2> friend qualified<T, Mask2>
>       qualified_cast(qualified src) {
>         return qualified<T, Mask2>(src.value_);
>       }
> };
>
> // Define a couple of type qualifiers
> const unsigned magic(1);
> const unsigned tainted(2);
>
> int main() {
>   int i(42);                             // Plain int
>   qualified<int, magic> m;               // Magic int
>   qualified<int, (magic | tainted)> mt;  // Magic, tainted int
>   mt = i;                                // OK
>   // m = mt;                             // This won't compile
>   m = qualified_cast<magic>(mt);         // But this will
>   return 0;
> }

[...]

> > #include <complex>
> >
> > int main()
> > {
> >     std::complex<float> x;
> >     sin(x);
> > }
>
> There's a big difference between this example and that of Ross. 3.4.2/2 says
> that for a template-id which is not a member template (since in both the
> cases the template arguments are of the fundamental types or are non-type
> parameters, there are no classes and namespace associated with them) the set
> of associated classes is empty and the set of associated namespaces is the
> namespace in which the template is defined.
>
> As a result in the case of your example, x having type 'std::complex<float>'
> has a set of associated namespaces S1: { std } and a set of associated
> classes S2: {   }. Because the function template sin is defined in the
> associated namespace std, it can be found by way of argument dependent
> lookup.
>
> In Ross's example mt has type '::qualified<int, magic|tainted>', hence its
> set of associated namespaces S1 is { :: }, and its set of associated classes
> S2: {   }. As the function template 'qualified_cast' is not declared in the
> global namespace, it cannot be found.

Ok. Now consider this:

template<class T> class X
{
public:
    friend void f(X const &) {}
};

int main()
{
  X<void> x;
  f(x);
}

x has type ::X<void>, S1 = { :: }, S2 = { }, f() is not declared in
the global namespace, but the call f(x) works. Odd stuff. :-)

--
Peter Dimov
Multi Media Ltd.

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: pdimov@mmltd.net (Peter Dimov)
Date: Thu, 7 Jun 2001 17:42:12 GMT
Raw View
"Andrei Iltchenko" <iltchenko@yahoo.com> wrote in message news:<9fm5j1$4s185$1@ID-62495.news.dfncis.de>...
> "Peter Dimov" <pdimov@mmltd.net> wrote in message
> news:7dc3b1ea.0106060702.21a7232d@posting.google.com...

[...]

> > > > > template <typename T, unsigned Mask> class qualified {
> > > > >   public:
> > > > >    // ...
> > > > >     template <unsigned Mask2> friend qualified<T, Mask2>
> > > > >       qualified_cast(qualified src) {
> > > > >         return qualified<T, Mask2>(src.value_);
> > > > >       }
> > > > > };
> > > > >
> > > > > // Define a couple of type qualifiers
> > > > > const unsigned magic(1);
> > > > > const unsigned tainted(2);
> > > > >
> > > > > int main() {
> > > > >   int i(42);                             // Plain int
> > > > >   qualified<int, magic> m;               // Magic int
> > > > >   qualified<int, (magic | tainted)> mt;  // Magic, tainted int
> > > > >   mt = i;                                // OK
> > > > >   // m = mt;                             // This won't compile
> > > > >   m = qualified_cast<magic>(mt);         // But this will
> > > > >   return 0;
> > > > > }
> >
> > [...]
> >
> > > Given that in the function call expression
> > > > m = qualified_cast<magic>(mt);
> > > the argument 'mt' is a template-id, whose arguments all have
> > > fundamental types, the set of classes associated with this argument is
> > > empty, and the set of associated namespaces comprises only the global
> > > namespace. As a result the name 'qualified_cast' cannot be found
> > > through argument dependent lookup.
> >
> > I don't understand. Why is 'mt' a template-id? 'mt' is a variable of
> > type qualified<int, magic | tainted>, and this class should have an
> > associated namespace (in this case the global namespace,) so
> > qualified_cast<> should be reachable through Koenig lookup.
>
> The argument dependent lookup is only concerned with the types of the
> arguments supplied to a function call expression. Do you disagree that the
> type of the object that the name 'mt' denotes is a template-id?

As I said, I'm not trying to disagree, but to understand. :-)

mt is of type 'qualified<int, magic | tainted>', right? Whether a type
can be called a template-id or not I don't know (I thought that the
template-id term refers to syntax, not semantics), but consider this
simple example:

#include <complex>

int main()
{
    std::complex<float> x;
    sin(x);
}

Here x is of type 'std::complex<float>', which is quite close in form.
Yet the argument-dependent lookup works fine in the function call
expression 'sin(x)'.

--
Peter Dimov
Multi Media Ltd.

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: "Andrei Iltchenko" <iltchenko@yahoo.com>
Date: Thu, 7 Jun 2001 21:30:04 GMT
Raw View
"Peter Dimov" <pdimov@mmltd.net> wrote in message
news:7dc3b1ea.0106070602.2a21f0d5@posting.google.com...
> "Andrei Iltchenko" <iltchenko@yahoo.com> wrote in message
news:<9fm5j1$4s185$1@ID-62495.news.dfncis.de>...
> > "Peter Dimov" <pdimov@mmltd.net> wrote in message
> > news:7dc3b1ea.0106060702.21a7232d@posting.google.com...
>
> [...]
>
> > > > > > template <typename T, unsigned Mask> class qualified {
> > > > > >   public:
> > > > > >    // ...
> > > > > >     template <unsigned Mask2> friend qualified<T, Mask2>
> > > > > >       qualified_cast(qualified src) {
> > > > > >         return qualified<T, Mask2>(src.value_);
> > > > > >       }
> > > > > > };
> > > > > >
> > > > > > // Define a couple of type qualifiers
> > > > > > const unsigned magic(1);
> > > > > > const unsigned tainted(2);
> > > > > >
> > > > > > int main() {
> > > > > >   int i(42);                             // Plain int
> > > > > >   qualified<int, magic> m;               // Magic int
> > > > > >   qualified<int, (magic | tainted)> mt;  // Magic, tainted int
> > > > > >   mt = i;                                // OK
> > > > > >   // m = mt;                             // This won't compile
> > > > > >   m = qualified_cast<magic>(mt);         // But this will
> > > > > >   return 0;
> > > > > > }
> > >
> > > [...]
> > >
> > > > Given that in the function call expression
> > > > > m = qualified_cast<magic>(mt);
> > > > the argument 'mt' is a template-id, whose arguments all have
> > > > fundamental types, the set of classes associated with this argument
is
> > > > empty, and the set of associated namespaces comprises only the
global
> > > > namespace. As a result the name 'qualified_cast' cannot be found
> > > > through argument dependent lookup.
> > >
> > > I don't understand. Why is 'mt' a template-id? 'mt' is a variable of
> > > type qualified<int, magic | tainted>, and this class should have an
> > > associated namespace (in this case the global namespace,) so
> > > qualified_cast<> should be reachable through Koenig lookup.
> >
> > The argument dependent lookup is only concerned with the types of the
> > arguments supplied to a function call expression. Do you disagree that
the
> > type of the object that the name 'mt' denotes is a template-id?
>
> As I said, I'm not trying to disagree, but to understand. :-)
>
> mt is of type 'qualified<int, magic | tainted>', right?

Right.


> Whether a type
> can be called a template-id or not I don't know (I thought that the
> template-id term refers to syntax, not semantics), but consider this
> simple example:
>
> #include <complex>
>
> int main()
> {
>     std::complex<float> x;
>     sin(x);
> }
>
> Here x is of type 'std::complex<float>', which is quite close in form.
> Yet the argument-dependent lookup works fine in the function call
> expression 'sin(x)'.

There's a big difference between this example and that of Ross. 3.4.2/2 says
that for a template-id which is not a member template (since in both the
cases the template arguments are of the fundamental types or are non-type
parameters, there are no classes and namespace associated with them) the set
of associated classes is empty and the set of associated namespaces is the
namespace in which the template is defined.

As a result in the case of your example, x having type 'std::complex<float>'
has a set of associated namespaces S1: { std } and a set of associated
classes S2: {   }. Because the function template sin is defined in the
associated namespace std, it can be found by way of argument dependent
lookup.

In Ross's example mt has type '::qualified<int, magic|tainted>', hence its
set of associated namespaces S1 is { :: }, and its set of associated classes
S2: {   }. As the function template 'qualified_cast' is not declared in the
global namespace, it cannot be found.


Cheers,

Andrei Iltchenko.



---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: Martin Sebor <sebor@roguewave.com>
Date: Tue, 5 Jun 2001 15:30:54 GMT
Raw View
Carl Daniel wrote:
>
> In another thread ("Custom type qualifiers..."), Ross Smith posted
> [abridged]:
>
> > template <typename T, unsigned Mask> class qualified {
> >   public:
> >    // ...
> >     template <unsigned Mask2> friend qualified<T, Mask2>
> >       qualified_cast(qualified src) {
> >         return qualified<T, Mask2>(src.value_);
> >       }
> > };
> >
> > // Define a couple of type qualifiers
> > const unsigned magic(1);
> > const unsigned tainted(2);
> >
> > int main() {
> >   int i(42);                             // Plain int
> >   qualified<int, magic> m;               // Magic int
> >   qualified<int, (magic | tainted)> mt;  // Magic, tainted int
> >   mt = i;                                // OK
> >   // m = mt;                             // This won't compile
> >   m = qualified_cast<magic>(mt);         // But this will
> >   return 0;
> > }
> >
> >
> > (Tested on GCC 2.95.3)
> >
>
> .... but apparently not tested with Comeau C++:
>
> Comeau C/C++ 4.2.45.2 (Apr 12 2001 10:06:52) for ONLINE_EVALUATION
> Copyright 1988-2001 Comeau Computing.  All rights reserved.
> MODE:strict errors C++
>
> "4893.c", line 42: error: identifier "qualified_cast" is undefined
>     m = qualified_cast<magic>(mt);         // But this will
>         ^
>
> 1 error detected in the compilation of "4893.c".
>
> So who's right?  Is the OP's code valid C++?  If it is, what exactly is the
> signature of the global function template qualified_cast<?????>(?????)?
>

I think the (original) code is actually ill-formed and gcc is in error
for not diagnosing it. Tbe friend template qualified_cast() isn't found
during ordinary lookup unless it is explicitly declared at namespace
scope (14.6.5). Comeau lets this slide except in strict ansi (-A) mode.

Regards
Martin

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: iltchenko@yahoo.com (Andrei Iltchenko)
Date: Tue, 5 Jun 2001 15:41:12 GMT
Raw View
"Carl Daniel" <carl@pixami.com> wrote in message news:<9fgdg5$erd@dispatch.concentric.net>...
> In another thread ("Custom type qualifiers..."), Ross Smith posted
> [abridged]:
>
> > template <typename T, unsigned Mask> class qualified {
> >   public:
> >    // ...
> >     template <unsigned Mask2> friend qualified<T, Mask2>
> >       qualified_cast(qualified src) {
> >         return qualified<T, Mask2>(src.value_);
> >       }
> > };
> >
> > // Define a couple of type qualifiers
> > const unsigned magic(1);
> > const unsigned tainted(2);
> >
> > int main() {
> >   int i(42);                             // Plain int
> >   qualified<int, magic> m;               // Magic int
> >   qualified<int, (magic | tainted)> mt;  // Magic, tainted int
> >   mt = i;                                // OK
> >   // m = mt;                             // This won't compile
> >   m = qualified_cast<magic>(mt);         // But this will
> >   return 0;
> > }
> >
> >
> > (Tested on GCC 2.95.3)
> >
>
> .... but apparently not tested with Comeau C++:
>
> Comeau C/C++ 4.2.45.2 (Apr 12 2001 10:06:52) for ONLINE_EVALUATION
> Copyright 1988-2001 Comeau Computing.  All rights reserved.
> MODE:strict errors C++
>
> "4893.c", line 42: error: identifier "qualified_cast" is undefined
>     m = qualified_cast<magic>(mt);         // But this will
>         ^
>
> 1 error detected in the compilation of "4893.c".
>
>
> So who's right?  Is the OP's code valid C++?  If it is, what exactly is the
> signature of the global function template qualified_cast<?????>(?????)?

Unfortunately the OP's code is not valid C++ and the EDG C++ front-end
issues a correct diagnostic.

The thing is that the following friend function declaration:
>     template <unsigned Mask2> friend qualified<T, Mask2>
>       qualified_cast(qualified src) {
>         return qualified<T, Mask2>(src.value_);
>       }
is just an indication to the compiler that the name 'qualified_cast'
is a member
of the nearest enclosing namespace, which happens to be the global
namespace. In no way does the declaration, which also happens to be a
definition, introduce the name 'qualified_cast' into the global
namespace scope.

Unless the function 'qualified_cast' is declared before the definition
of the class 'qualified' or after it, the name 'qualified_cast' can
only be found using argument-dependent lookup through the function
only argument's associated classes.

Given that in the function call expression
> m = qualified_cast<magic>(mt);
the argument 'mt' is a template-id, whose arguments all have
fundamental types, the set of classes associated with this argument is
empty, and the set of associated namespaces comprises only the global
namespace. As a result the name 'qualified_cast' cannot be found
through argument dependent lookup.

The only way to make the example well-formed is to add relevant
declaration of the function template 'qualified_cast' to the global
namespace. I guess you'll be a bit surprised at the form that the
declarations shall have:

template<unsigned Mask2>
qualified<unsigned,Mask2>  qualified_cast(qualified<unsigned,3>);

This one will suffice for the example shown. It follows that if you
decide to issue a statement 'm = qualified_cast<magic>(m)', another
global scope declaration of the form:
template<unsigned Mask2>
qualified<unsigned,Mask2>  qualified_cast(qualified<unsigned,1>);
will be necessary. And so on, and so forth, which in my opinion makes
the example a nuisance.


Regards,

Andrei Iltchenko.

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: "Carl Daniel" <carl@pixami.com>
Date: Mon, 4 Jun 2001 18:06:20 GMT
Raw View
In another thread ("Custom type qualifiers..."), Ross Smith posted
[abridged]:

> template <typename T, unsigned Mask> class qualified {
>   public:
>    // ...
>     template <unsigned Mask2> friend qualified<T, Mask2>
>       qualified_cast(qualified src) {
>         return qualified<T, Mask2>(src.value_);
>       }
> };
>
> // Define a couple of type qualifiers
> const unsigned magic(1);
> const unsigned tainted(2);
>
> int main() {
>   int i(42);                             // Plain int
>   qualified<int, magic> m;               // Magic int
>   qualified<int, (magic | tainted)> mt;  // Magic, tainted int
>   mt = i;                                // OK
>   // m = mt;                             // This won't compile
>   m = qualified_cast<magic>(mt);         // But this will
>   return 0;
> }
>
>
> (Tested on GCC 2.95.3)
>

.... but apparently not tested with Comeau C++:

Comeau C/C++ 4.2.45.2 (Apr 12 2001 10:06:52) for ONLINE_EVALUATION
Copyright 1988-2001 Comeau Computing.  All rights reserved.
MODE:strict errors C++

"4893.c", line 42: error: identifier "qualified_cast" is undefined
    m = qualified_cast<magic>(mt);         // But this will
        ^

1 error detected in the compilation of "4893.c".


So who's right?  Is the OP's code valid C++?  If it is, what exactly is the
signature of the global function template qualified_cast<?????>(?????)?

-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.research.att.com/~austern/csc/faq.html                ]





Author: pdimov@mmltd.net (Peter Dimov)
Date: Wed, 6 Jun 2001 20:17:31 GMT
Raw View
iltchenko@yahoo.com (Andrei Iltchenko) wrote in message news:<b5545f76.0106050740.52cc8166@posting.google.com>...
> "Carl Daniel" <carl@pixami.com> wrote in message news:<9fgdg5$erd@dispatch.concentric.net>...
> > In another thread ("Custom type qualifiers..."), Ross Smith posted
> > [abridged]:
> >
> > > template <typename T, unsigned Mask> class qualified {
> > >   public:
> > >    // ...
> > >     template <unsigned Mask2> friend qualified<T, Mask2>
> > >       qualified_cast(qualified src) {
> > >         return qualified<T, Mask2>(src.value_);
> > >       }
> > > };
> > >
> > > // Define a couple of type qualifiers
> > > const unsigned magic(1);
> > > const unsigned tainted(2);
> > >
> > > int main() {
> > >   int i(42);                             // Plain int
> > >   qualified<int, magic> m;               // Magic int
> > >   qualified<int, (magic | tainted)> mt;  // Magic, tainted int
> > >   mt = i;                                // OK
> > >   // m = mt;                             // This won't compile
> > >   m = qualified_cast<magic>(mt);         // But this will
> > >   return 0;
> > > }

[...]

> Given that in the function call expression
> > m = qualified_cast<magic>(mt);
> the argument 'mt' is a template-id, whose arguments all have
> fundamental types, the set of classes associated with this argument is
> empty, and the set of associated namespaces comprises only the global
> namespace. As a result the name 'qualified_cast' cannot be found
> through argument dependent lookup.

I don't understand. Why is 'mt' a template-id? 'mt' is a variable of
type qualified<int, magic | tainted>, and this class should have an
associated namespace (in this case the global namespace,) so
qualified_cast<> should be reachable through Koenig lookup.

--
Peter Dimov
Multi Media Ltd.

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: "Andrei Iltchenko" <iltchenko@yahoo.com>
Date: Wed, 6 Jun 2001 21:05:09 GMT
Raw View
"Peter Dimov" <pdimov@mmltd.net> wrote in message
news:7dc3b1ea.0106060702.21a7232d@posting.google.com...
> iltchenko@yahoo.com (Andrei Iltchenko) wrote in message
news:<b5545f76.0106050740.52cc8166@posting.google.com>...
> > "Carl Daniel" <carl@pixami.com> wrote in message
news:<9fgdg5$erd@dispatch.concentric.net>...
> > > In another thread ("Custom type qualifiers..."), Ross Smith posted
> > > [abridged]:
> > >
> > > > template <typename T, unsigned Mask> class qualified {
> > > >   public:
> > > >    // ...
> > > >     template <unsigned Mask2> friend qualified<T, Mask2>
> > > >       qualified_cast(qualified src) {
> > > >         return qualified<T, Mask2>(src.value_);
> > > >       }
> > > > };
> > > >
> > > > // Define a couple of type qualifiers
> > > > const unsigned magic(1);
> > > > const unsigned tainted(2);
> > > >
> > > > int main() {
> > > >   int i(42);                             // Plain int
> > > >   qualified<int, magic> m;               // Magic int
> > > >   qualified<int, (magic | tainted)> mt;  // Magic, tainted int
> > > >   mt = i;                                // OK
> > > >   // m = mt;                             // This won't compile
> > > >   m = qualified_cast<magic>(mt);         // But this will
> > > >   return 0;
> > > > }
>
> [...]
>
> > Given that in the function call expression
> > > m = qualified_cast<magic>(mt);
> > the argument 'mt' is a template-id, whose arguments all have
> > fundamental types, the set of classes associated with this argument is
> > empty, and the set of associated namespaces comprises only the global
> > namespace. As a result the name 'qualified_cast' cannot be found
> > through argument dependent lookup.
>
> I don't understand. Why is 'mt' a template-id? 'mt' is a variable of
> type qualified<int, magic | tainted>, and this class should have an
> associated namespace (in this case the global namespace,) so
> qualified_cast<> should be reachable through Koenig lookup.

The argument dependent lookup is only concerned with the types of the
arguments supplied to a function call expression. Do you disagree that the
type of the object that the name 'mt' denotes is a template-id?


Cheers,

Andrei Iltchenko.



---
[ 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.research.att.com/~austern/csc/faq.html                ]