Topic: Bad influence of the visibility of a function template?


Author: pdimov@mmltd.net (Peter Dimov)
Date: Sun, 11 May 2003 19:23:03 +0000 (UTC)
Raw View
francis@robinton.demon.co.uk (Francis Glassborow) wrote in message news:<$m57XVDuWhv+EwsR@robinton.demon.co.uk>...
> In article <7dc3b1ea.0305100316.6a29a1f@posting.google.com>, Peter Dimov
> <pdimov@mmltd.net> writes
> >The problem is that accessing the member R of X<int> causes X<int>'s
> >definition to be instantiated. X<int>'s definition is invalid since
> >typename int::R is invalid. Compile-time error since "attempting to
> >instantiate an invalid type" is not on the list.
>
> If it is really that specific then we can easily fix the problem.
> Perhaps implementors could comment on this. Would adding that case fix
> it?

It is quite general, in fact, as most other cases that are explicitly
listed fall under the "attempt to generate an invalid type" umbrella.
It has been my impression that 14.8.2/2 explicitly lists failure
reasons to avoid introducing a general "does this construct compile?"
primitive which does not fit well the current compiler codebases (as
it requires potentially unlimited backtracking on error.) But I may be
wrong. :-)

Note too that generalizing 14.8.2/2, while convenient for library
implementors, can cause some odd errors to be masked by type deduction
failures, silently dropping a candidate from the list of viable
functions. One such example under today's rules:

template<class It> typename std::iterator_traits<It>::distance_type
distance(It first, It last);

Why does this function work under compiler A but fails with "no
matching function in call to 'advance'" under compiler B, when invoked
with correct arguments (two iterators that form a range)?

---
[ 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: pdimov@mmltd.net (Peter Dimov)
Date: Sun, 11 May 2003 19:23:12 +0000 (UTC)
Raw View
hinnant@metrowerks.com (Howard Hinnant) wrote in message news:<070520031111153877%hinnant@metrowerks.com>...
> Unfortunately this doesn't quite work on std::distance, but the same
> concept that makes this work can be easily applied to std::distance:
>
> template <class T, bool = is_input_iterator<T>::value>
> struct get_iterator_traits {};
>
> template <class Iterator>
> struct get_iterator_traits<Iterator, true>
> {
>    typedef typename Iterator::difference_type difference_type;
>    typedef typename Iterator::value_type value_type;
>    typedef typename Iterator::pointer pointer;
>    typedef typename Iterator::reference reference;
>    typedef typename Iterator::iterator_category iterator_category;
> };
>
> template <class InputIterator>
> typename get_iterator_traits<InputIterator>::difference_type
> distance(InputIterator first, InputIterator last);
>
> With the above modification, Francis' original distance demo now
> compiles as desired.

It would be much easier to fix iterator_traits instead:

template <class It> struct iterator_traits
{
};

and provide specializations for all iterators. Breaks existing code! Shock! Horror!

Maybe some day. ;-)

---
[ 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: cbarron3@ix.netcom.com (Carl Barron)
Date: Mon, 12 May 2003 18:19:11 +0000 (UTC)
Raw View
Hyman Rosen <hyrosen@mail.com> wrote:

> Francis Glassborow wrote:
> > In article <1052142492.54500@master.nyc.kbcfp.com>, Hyman Rosen
> > <hyrosen@mail.com> writes
> >
> >> I think that Comeau just has a bug, unless someone can quote
> >> chapter and verse at me to demonstrate otherwise.
> >
> > Try 14.8.3/1
> >
> > The argument deduction succeeds and so the compiler is required to
> > instantiate the function -- which it cannot.
>
> 14.8.3/1 requires argument deduction *and checking* to succeed.
> In this case, checking fails.
>
  it says ... and checking of any explicit template arguments(14.3)...

not FUNCTION ARGUMENTS. Further return type of a function is not a
function argument...

---
[ 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: hyrosen@mail.com (Hyman Rosen)
Date: Mon, 12 May 2003 23:30:38 +0000 (UTC)
Raw View
Carl Barron wrote:
>   it says ... and checking of any explicit template arguments(14.3)...
> not FUNCTION ARGUMENTS. Further return type of a function is not a
> function argument...

That's not the what's causing the problem. The implementors are saying
that the list of reasons to fail enumerated in 14.8.2/2 are applied only
to the form of the substituted-into parameters, not to any types that
might appear in instantiations forced by those substitutions, and a form
such as X<T>::R is not one of the enumerated failure modes, and will not
cause deduction to fail, even though it immediately results in a compilation
error because the compiler is forced to instantiate a class which is
ill-formed.

I can understand the reasoning, so if we want it to work in the more
logical (IMHO) way, the committee should issue a correction.

---
[ 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: hyrosen@mail.com (Hyman Rosen)
Date: Thu, 8 May 2003 21:08:00 +0000 (UTC)
Raw View
Francis Glassborow wrote:
> So do you know of any compiler that does what both of us want? The
> compiler writers seem to believe that what they are doing is what is
> required.

It could just be that they haven't encountered this case before
and it fell into some default behavior that they wouldn't want
once they see it.

What does VC++ 7 do? Anyone know?

---
[ 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: dave@boost-consulting.com (David Abrahams)
Date: Fri, 9 May 2003 23:31:39 +0000 (UTC)
Raw View
hyrosen@mail.com (Hyman Rosen) writes:

> You already have to match all the parameters. I don't see why
> adding the return type is such a burden. If the code was this:
>
>      template <typename T> struct X { typedef typename T::R R; };
>      template <typename T> void f(T, typename X<T>::R);
>      void f(int, long);
>      int main() { f(1, 2); }
>
> would that make a difference in your interpretation?
> Comeau on-line rejects this code exactly the same way.
> I think it's just a plain bug.

In the standard, maybe.  The compiler is implementing the standard
semantics.

14.8.2/2 enumerates the list of constructs which causes type
     deduction to fail, and

        typename X<T>::R

     is not in the list.  Quite a few people are unhappy about it,
     but that's what the specification says.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

---
[ 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: pdimov@mmltd.net (Peter Dimov)
Date: Sun, 11 May 2003 00:38:07 +0000 (UTC)
Raw View
dave@boost-consulting.com (David Abrahams) wrote in message news:<u65oj90fw.fsf@boost-consulting.com>...
> hyrosen@mail.com (Hyman Rosen) writes:
>
> > You already have to match all the parameters. I don't see why
> > adding the return type is such a burden. If the code was this:
> >
> >      template <typename T> struct X { typedef typename T::R R; };
> >      template <typename T> void f(T, typename X<T>::R);
> >      void f(int, long);
> >      int main() { f(1, 2); }
> >
> > would that make a difference in your interpretation?
> > Comeau on-line rejects this code exactly the same way.
> > I think it's just a plain bug.
>
> In the standard, maybe.  The compiler is implementing the standard
> semantics.
>
> 14.8.2/2 enumerates the list of constructs which causes type
>      deduction to fail, and
>
>         typename X<T>::R
>
>      is not in the list.  Quite a few people are unhappy about it,
>      but that's what the specification says.

I think it's more subtle than that. typename X<T>::R _is_ in the list.
Type deduction would have failed if there was a valid X<T> that did
not contain an R, or contained a nontype R (third sub-bullet).

The problem is that accessing the member R of X<int> causes X<int>'s
definition to be instantiated. X<int>'s definition is invalid since
typename int::R is invalid. Compile-time error since "attempting to
instantiate an invalid type" is not on the list.

---
[ 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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Sun, 11 May 2003 09:27:55 +0000 (UTC)
Raw View
In article <7dc3b1ea.0305100316.6a29a1f@posting.google.com>, Peter Dimov
<pdimov@mmltd.net> writes
>The problem is that accessing the member R of X<int> causes X<int>'s
>definition to be instantiated. X<int>'s definition is invalid since
>typename int::R is invalid. Compile-time error since "attempting to
>instantiate an invalid type" is not on the list.

If it is really that specific then we can easily fix the problem.
Perhaps implementors could comment on this. Would adding that case fix
it?


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Wed, 7 May 2003 04:27:44 +0000 (UTC)
Raw View
In article <dLtCGVKhwtt+Ew6E@robinton.demon.co.uk>, Francis Glassborow
<francis@robinton.demon.co.uk> writes
>The definition of an exported type does not need to be visible at the
>point of use. Now if the return is by pointer or reference (sorry, I
>overlooked that requirement) the compiler does not need the type to be
>complete. Therefore it has no way to determine if the template can be
>instantiated.

Tiredness seems to have taken over. I seem to have elided in my thinking
the concepts of a class template declaration and a class template
definition (possibly because I was thinking of function templates where
there is no third 'implementation' item)

To be honest this entire area is a minefield and it is hardly surprising
that the problem of function template instantiation for the purposes of
overload resolution has taken five years to surface (at least in my neck
of the woods)


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Wed, 7 May 2003 17:10:04 +0000 (UTC)
Raw View
In article <1052230491.501074@master.nyc.kbcfp.com>, Hyman Rosen
<hyrosen@mail.com> writes
>> Now if the return is by pointer or reference (sorry, I overlooked
>> that requirement) the compiler does not need the type to be complete.
>> Therefore it has no way to determine if the template can be
>> instantiated.
>
>I still don't see how this gets around the requirement that after
>argument deduction, all parameter uses in non-deduced contexts have
>to be checked for correctness, or type deduction fails.

Just parameters or return types? Anyway, this now places a larger
requirement on function templates in that the definition of and
dependant types must be visible.

I think that I can live with either rigid application of this rule
(though it can make overload resolution extremely expensive) or removal
of this requirement so that overload resolution proceeds and the
selected function may then be ill-formed. What I cannot find acceptable
is that the ill-formedness of a potential candidate for the overload set
results in failure even when that candidate is not chosen.


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: hinnant@metrowerks.com (Howard Hinnant)
Date: Wed, 7 May 2003 17:54:45 +0000 (UTC)
Raw View
In article <vMD+nKCYF4t+EwNG@robinton.demon.co.uk>, Francis Glassborow
<francis@robinton.demon.co.uk> wrote:

| To be honest this entire area is a minefield and it is hardly surprising
| that the problem of function template instantiation for the purposes of
| overload resolution has taken five years to surface (at least in my neck
| of the woods)

Imho, "this area" is a classic demonstration of the need for
"restricted templates" or "constrained genericity".  And this need has
come up repeatedly over the years.

The fully generic relational operators were overly greedy and needed to
be constrained.  They were constrained by hiding them in namespace
rel_ops.

23.1.1, paragraphs 9-11 describe the second case I'm aware of.  Namely
the member template functions of the containers that take
InputIterator's.  The basic problem is that the member function
templates too greedily match signatures.  A clean solution would
somehow restrict instantiation of these signatures to types that
satisfied the concept of input iterator.

The third time I saw this come up was in '99 when we shipped templated
math functions (as an extension) to handle integral arguments (tgmath.h
style).  What we really needed was to ship templates restricted to
integral or arithmetic types.  We didn't ship this solution for long.
It broke our customer's code (in ways very similar to the distance
example).  We found other solutions for this problem.

I've seen it come up occasionally in minor examples here and there
since (once on boost).  You can get the exact same type of error with
std::count and std::count_if.

And you can get very similar errors with almost every namespace scope
function templated on iterator types (<iterator>, <algorithm>,
<numeric>):

#include <iterator>

using namespace std;

struct Student {};

void advance(Student& s, int grade);

int main()
{
   Student s;
   advance(s, 'A');
}

Error   : 'difference_type' is not a member of class 'Student'
 (point of instantiation: 'main()')
  (instantiating: 'std::advance<Student, char>(Student &, char)')
   (instantiating: 'std::iterator_traits<Student>')
iterator line 323   typedef typename Iterator::difference_type
difference_type;

And I agree with Francis that this is not a problem with using
directives.  They simply make it easier to demonstrate the problem.  A
large programming project could easily mix similar function templates
and ordinary functions in the same namespace.

The problem is the creation of a function template whose signature
accepts all types, but whose semantics accept only a small subset of
types:

template <class InputIterator, class Distance>
void
advance(InputIterator& i, Distance n);

These names are very suggestive.  The mind starts to constrain these
template parameters automatically.  The compiler does not.  It might as
well be written:

template <class T, class U>
void
advance(T& i, U n);

It would be nice if we could say something like:

template
<
   class InputIterator : is_input_iterator<InputIterator>::value,
   class Distance : numeric_limits<Distance>::is_integer
>
void
advance(InputIterator& i, Distance n);

template <
   class InputIterator : is_input_iterator<InputIterator>::value
>
typename iterator_traits<InputIterator>::difference_type
distance(InputIterator first, InputIterator last);

This would tell the compiler to only attempt to include an
instantiation of this function template in the viable overload set if
the types met some basic requirements (e.g. either is a non-const
pointer or has a nested member type called iterator_category that is
convertible to std::input_iterator_tag).  Otherwise look for other
overloads.

Unfortunately, this is not currently legal C++.  Maybe it will be some
day.

In the mean time, you can get close to the above restricted template:

template <bool b, class T = void>
    struct restrict_to {};
template <class T>
    struct restrict_to<true, T> {typedef T type;};

template <class InputIterator, class Distance>
typename restrict_to
<
   is_input_iterator<InputIterator>::value &&
   numeric_limits<Distance>::is_integer,
   void
>::type
advance(InputIterator& i, Distance n);

"restrict_to" is also often spelled "enable_if".  (See the June '03 CUJ
for more details and applications).

Unfortunately this doesn't quite work on std::distance, but the same
concept that makes this work can be easily applied to std::distance:

template <class T, bool = is_input_iterator<T>::value>
struct get_iterator_traits {};

template <class Iterator>
struct get_iterator_traits<Iterator, true>
{
   typedef typename Iterator::difference_type difference_type;
   typedef typename Iterator::value_type value_type;
   typedef typename Iterator::pointer pointer;
   typedef typename Iterator::reference reference;
   typedef typename Iterator::iterator_category iterator_category;
};

template <class InputIterator>
typename get_iterator_traits<InputIterator>::difference_type
distance(InputIterator first, InputIterator last);

With the above modification, Francis' original distance demo now
compiles as desired.

--
Howard Hinnant
Metrowerks

---
[ 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: hinnant@metrowerks.com (Howard Hinnant)
Date: Wed, 7 May 2003 21:04:04 +0000 (UTC)
Raw View
In article <070520031111153877%hinnant@metrowerks.com>, Howard Hinnant
<hinnant@metrowerks.com> wrote:

| template <class T, bool = is_input_iterator<T>::value>
| struct get_iterator_traits {};
|
| template <class Iterator>
| struct get_iterator_traits<Iterator, true>
| {
|    typedef typename Iterator::difference_type difference_type;
|    typedef typename Iterator::value_type value_type;
|    typedef typename Iterator::pointer pointer;
|    typedef typename Iterator::reference reference;
|    typedef typename Iterator::iterator_category iterator_category;
| };

Oops, copy/paste think-o.

Substitute
   iterator_traits<Iterator>::
for
   Iterator::

--
Howard Hinnant
Metrowerks

---
[ 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: hyrosen@mail.com (Hyman Rosen)
Date: Wed, 7 May 2003 21:04:50 +0000 (UTC)
Raw View
Francis Glassborow wrote:
> Just parameters or return types?

14.8.2/4 is talking about the function type, which means that it
is speaking about the function declaration. It says that template
parameters, whether deduced or explicit, are substitued into the
non-deduced contexts, an dthe result must be a legal function
type. I would assume that this means that the function body does
not need to be instantiated at that point.

 > Anyway, this now places a larger requirement on function templates
 > in that the definition of and dependant types must be visible.

Why do you think that this is a new or larger requirement?
As far as I know, overload resolution has always potentially
required the instantiation of specializations of function
template declarations, and when you do that, you instantiate
the whole declaration, not selected bits.

> I think that I can live with either rigid application of this rule
> (though it can make overload resolution extremely expensive)

You already have to match all the parameters. I don't see why
adding the return type is such a burden. If the code was this:

     template <typename T> struct X { typedef typename T::R R; };
     template <typename T> void f(T, typename X<T>::R);
     void f(int, long);
     int main() { f(1, 2); }

would that make a difference in your interpretation?
Comeau on-line rejects this code exactly the same way.
I think it's just a plain bug.

> or removal of this requirement so that overload resolution proceeds
 > and the selected function may then be ill-formed.

Yuck. It doesn't match the intent of 14.8.2/4 and SFINAE, and is of
no possible use to the programmer.

> What I cannot find acceptable is that the ill-formedness of a potential
 > candidate for the overload set results in failure even when that candidate
 > is not chosen.

Me either.

---
[ 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: hinnant@metrowerks.com (Howard Hinnant)
Date: Thu, 8 May 2003 17:14:26 +0000 (UTC)
Raw View
In article <cu9SPJKg2Yt+Ewoz@robinton.demon.co.uk>, Francis Glassborow
<francis@robinton.demon.co.uk> wrote:

| In article <b93rp6$6m4$1@newsserver.rrzn.uni-hannover.de>, Thomas Witt
| <witt@ive.uni-hannover.de> writes
| >Francis Glassborow wrote:
| >>  ill-formed unless x_traits<int> has been defined and provides a type
| >>named return_type. This is irrespective of whether I have declared a
| >>non-template function foo(int, int) [ with any return type]
| >>
| >
| >AFAICS this is slightly worng. If x_traits<int> is defined and has no
| >nested return_type typedef, SFINAE kicks in and the templated foo is
| >removed from the overload set. There are compilers that accept the code
| >even if xtraits<int> is not defined, though I don't know if this is
| >legal code.
| >
| >What causes problems is the typedef forwarding in iterator_traits. I.e
| >if xtraits is defined as follows your lost.
| >
| >template <class T>
| >struct xtraits
| >{
| >  typedef typename T::result_type result_type;
| >};

Nice problem statement.

| So it seems. However I still believe that the compiler should either be
| not attempting to look at the return type until after overload
| resolution, or such a failure should result in the template being
| removed from the overload set.

This would not be a complete fix.  Consider:

template <class InputIterator>
void
advance(InputIterator first,
        typename iterator_traits<InputIterator>::difference_type n);

Same problem, but it has now moved to the argument list (this isn't
meant to be the prototype for std::advance, but it could have been).

A complete fix would involve restricting the types InputIterator can be
matched to.  Failure of a type to be matched to InputIterator should
not cause a compile time error, but simply cause advance to not be
added to the list of viable overloads.

--
Howard Hinnant
Metrowerks

---
[ 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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Thu, 8 May 2003 18:57:11 +0000 (UTC)
Raw View
In article <1052341370.87920@master.nyc.kbcfp.com>, Hyman Rosen
<hyrosen@mail.com> writes
>You already have to match all the parameters. I don't see why
>adding the return type is such a burden. If the code was this:
>
>    template <typename T> struct X { typedef typename T::R R; };
>    template <typename T> void f(T, typename X<T>::R);
>    void f(int, long);
>    int main() { f(1, 2); }
>
>would that make a difference in your interpretation?
>Comeau on-line rejects this code exactly the same way.
>I think it's just a plain bug.


If so it is a widely shared one.

And how should the compiler deal with the above code if X is only
declared and not defined at this point?


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Thu, 8 May 2003 18:57:13 +0000 (UTC)
Raw View
In article <1052341370.87920@master.nyc.kbcfp.com>, Hyman Rosen
<hyrosen@mail.com> writes
>> What I cannot find acceptable is that the ill-formedness of a potential
>> candidate for the overload set results in failure even when that candidate
>> is not chosen.
>
>Me either.

So do you know of any compiler that does what both of us want? The
compiler writers seem to believe that what they are doing is what is
required.


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: hyrosen@mail.com (Hyman Rosen)
Date: Thu, 8 May 2003 21:07:54 +0000 (UTC)
Raw View
Francis Glassborow wrote:
>> I think it's just a plain bug.
> If so it is a widely shared one.

It wouldn't be the first time.

> And how should the compiler deal with the above code if X is only
> declared and not defined at this point?

Compilation error. Trying an instantiation of a function template
should not cause an error if the instantiation fails because of an
illegal type. But if the instantiation attempt requires certain
classes to be complete which are not, that is just a plain error.

It's a simple distinction. In the first case, there is no error
in the code. Templates can be instantiated for some types but
not others, and Specialization Failure Is Not An Error. In the
second case, the code is incorrectly written - you have failed
to provide a complete class where one is needed.

---
[ 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: witt@ive.uni-hannover.de (Thomas Witt)
Date: Sun, 4 May 2003 21:43:06 +0000 (UTC)
Raw View
Francis Glassborow wrote:
>
> ill-formed unless x_traits<int> has been defined and provides a type
> named return_type. This is irrespective of whether I have declared a
> non-template function foo(int, int) [ with any return type]
>

AFAICS this is slightly worng. If x_traits<int> is defined and has no
nested return_type typedef, SFINAE kicks in and the templated foo is
removed from the overload set. There are compilers that accept the code
even if xtraits<int> is not defined, though I don't know if this is
legal code.

What causes problems is the typedef forwarding in iterator_traits. I.e
if xtraits is defined as follows your lost.

template <class T>
struct xtraits
{
   typedef typename T::result_type result_type;
};

Thomas

--
Dipl.-Ing. Thomas Witt
Institut fuer Verkehrswesen, Eisenbahnbau und -betrieb, Universitaet
Hannover
voice: +49(0) 511 762 - 4273, fax: +49(0) 511 762-3001
http://www.ive.uni-hannover.de

---
[ 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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Sun, 4 May 2003 21:43:22 +0000 (UTC)
Raw View
In article <3EB51F79.F90DDB73@acm.org>, Pete Becker <petebecker@acm.org>
writes
>Francis Glassborow wrote:
>>
>>  #include <iostream>
>>
>>  using namespace std;
>>
>>  typedef int point2d;
>>  double distance(point2d const & from, point2d const & to);
>>
>>  int main(){
>>                  point2d abc(0), xyz(0);
>>                  cout << distance(abc, xyz);
>>
>>  }
>>
>> Look at the above code. Do you think it ought to compile (it doesn't on
>> at least two well respected compilers)
>>
>> Is this failure a defect in the Standard? Probably not as I guess those
>> responsible said what they meant but as sure as hell it isn't what any
>> ordinary programmer would expect. And yes you can work round by
>> replacing distance with ::distance but I think that is rather beside the
>> point.
>>
>
>Thus illustrating why 'using namespace std;' is a bad idea.

Only in part, because with the directive the code can be fixed by
writing ::distance instead of distance. However if you used a using
declaration it cannot be fixed.

If I want to actually overload across name spaces, using directives work
and fully elaborated names can be used for disambiguation.

Anyway, the problem isn't actually with the using directive, that only
created the surprise for the novice.


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Mon, 5 May 2003 01:09:58 +0000 (UTC)
Raw View
In article <b93rp6$6m4$1@newsserver.rrzn.uni-hannover.de>, Thomas Witt
<witt@ive.uni-hannover.de> writes
>Francis Glassborow wrote:
>>  ill-formed unless x_traits<int> has been defined and provides a type
>>named return_type. This is irrespective of whether I have declared a
>>non-template function foo(int, int) [ with any return type]
>>
>
>AFAICS this is slightly worng. If x_traits<int> is defined and has no
>nested return_type typedef, SFINAE kicks in and the templated foo is
>removed from the overload set. There are compilers that accept the code
>even if xtraits<int> is not defined, though I don't know if this is
>legal code.
>
>What causes problems is the typedef forwarding in iterator_traits. I.e
>if xtraits is defined as follows your lost.
>
>template <class T>
>struct xtraits
>{
>  typedef typename T::result_type result_type;
>};

So it seems. However I still believe that the compiler should either be
not attempting to look at the return type until after overload
resolution, or such a failure should result in the template being
removed from the overload set.


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Mon, 5 May 2003 01:09:59 +0000 (UTC)
Raw View
In article <jHeta.37148$D%4.14548@nwrdny03.gnilink.net>, Hyman Rosen
<hyrosen@mail.com> writes
>Francis Glassborow wrote:
>> template <typename T> class x_traits;
>> template<typename T> x_traits<T>::return_type foo(T, T);
>> makes the call foo(1,1); ill-formed unless x_traits<int> has been defined
>> and provides a type named return_type. This is irrespective of whether I
>> have declared a non-template function foo(int, int) [ with any return type]
>
>I don't know why you think this, but you're wrong. Perhaps you are getting
>confused because you forgot a 'typename'?
>    template<typename T> typename x_traits<T>::return_type foo(T, T);
>
>If you look at 14.8.2/4, you will see it explicitly stated that after
>argument deduction, if substitution into non-deduced contexts results
>in an illegal type, type deduction fails (which is not an error).
>
>Comeau on-line also compiles the code with no errors.

You are quite right, but it does not compile (note, no namespaces, no
Standard Library, no using declarations or directives.

I suspect that 14.8.2/4 does not apply because this is a deduced context
but I cannot be certain because there is too much interacting text.



  template<typename _Iterator>
    struct iterator_traits {
      typedef typename _Iterator::iterator_category iterator_category;
      typedef typename _Iterator::value_type        value_type;
      typedef typename _Iterator::difference_type   difference_type;
      typedef typename _Iterator::pointer           pointer;
      typedef typename _Iterator::reference         reference;
    };


template<typename T>
typename iterator_traits<T>::difference_type distance(T, T);

int distance(int, int);

int main(){
        distance(1, 1);
}


IOWs, if it only sees a forward declaration everything is fine, but the
minute I include a definition it falls over.

I suspect, but have not tested, that that means if I use export my code
compiles, but not otherwise.


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: petebecker@acm.org (Pete Becker)
Date: Mon, 5 May 2003 01:10:14 +0000 (UTC)
Raw View
Francis Glassborow wrote:
>
> In article <3EB51F79.F90DDB73@acm.org>, Pete Becker <petebecker@acm.org>
> writes
> >Francis Glassborow wrote:
> >>
> >>  #include <iostream>
> >>
> >>  using namespace std;
> >>
> >>  typedef int point2d;
> >>  double distance(point2d const & from, point2d const & to);
> >>
> >>  int main(){
> >>                  point2d abc(0), xyz(0);
> >>                  cout << distance(abc, xyz);
> >>
> >>  }
> >>
> >> Look at the above code. Do you think it ought to compile (it doesn't on
> >> at least two well respected compilers)
> >>
> >> Is this failure a defect in the Standard? Probably not as I guess those
> >> responsible said what they meant but as sure as hell it isn't what any
> >> ordinary programmer would expect. And yes you can work round by
> >> replacing distance with ::distance but I think that is rather beside the
> >> point.
> >>
> >
> >Thus illustrating why 'using namespace std;' is a bad idea.
>
> Only in part, because with the directive the code can be fixed by
> writing ::distance instead of distance. However if you used a using
> declaration it cannot be fixed.
>

Yes, different examples lead to different conclusions. I replied to the
example you gave.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

---
[ 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: jdennett@acm.org (James Dennett)
Date: Mon, 5 May 2003 04:58:47 +0000 (UTC)
Raw View
Pete Becker wrote:
> Francis Glassborow wrote:
>
>> #include <iostream>
>>
>> using namespace std;
>>
>> typedef int point2d;
>> double distance(point2d const & from, point2d const & to);
>>
>> int main(){
>>                 point2d abc(0), xyz(0);
>>                 cout << distance(abc, xyz);
>>
>> }
>>
>>Look at the above code. Do you think it ought to compile (it doesn't on
>>at least two well respected compilers)
>>
>>Is this failure a defect in the Standard? Probably not as I guess those
>>responsible said what they meant but as sure as hell it isn't what any
>>ordinary programmer would expect. And yes you can work round by
>>replacing distance with ::distance but I think that is rather beside the
>>point.
>>
>
>
> Thus illustrating why 'using namespace std;' is a bad idea.
>

But also highlighting another problem which isn't related to
namespaces:

template <typename ConstrainedType>
typename ConstrainedType::RequiredNestedType
function1(ConstrainedType);

template <typename T> struct traits {
   typedef typename T::nested_type nested_type;
};

template <typename ConstrainedType>
typename traits<ConstrainedType>::RequiredNestedType
function2(ConstrainedType);

void function1(int const & from) { }
void function2(int const & from) { }

int main(){
   function1(0);
   function2(0);
}

Where function1(0) compiles cleanly, but function2(0)
does not with either como or g++, and I think they're
within their rights to reject it.

-- James.

---
[ 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: hyrosen@mail.com (Hyman Rosen)
Date: Mon, 5 May 2003 15:25:30 +0000 (UTC)
Raw View
James Dennett wrote:
> Where function1(0) compiles cleanly, but function2(0)
> does not with either como or g++, and I think they're
> within their rights to reject it.

I disagree. 14.8.2/4 explicitly says
     When all template arguments have been deduced,
     all uses of template parameters in nondeduced
     contexts are replaced with the corresponding
     deduced argument values. If the substitution
     results in an invalid type, as described above,
     type deduction fails.

For the function2 case, ConstrainedType will be
deduced as int, replacement will occur to form
traits<int>::RequireNestedType, and that will
result in an invalid type "as described above".
In 14.8.2s6, we are told that one of the things
that causes type deduction to fail is attempting
to use a type as a qualifier when the type does
not contain the qualified name, and in 14.8.2s5
there is similar language for attempting to use
a non-class type in a qualified name. Now, since
traits<int> cannot even be instantiated, it is
not a class type, and if you argue that it is, it
certainly doesn't contain the required name.

---
[ 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: hyrosen@mail.com (Hyman Rosen)
Date: Mon, 5 May 2003 15:25:59 +0000 (UTC)
Raw View
Francis Glassborow wrote:
> You are quite right, but it does not compile

Sorry, your sample compiles; I didn't try the 'distance' case.

> I suspect that 14.8.2/4 does not apply because this is a deduced context
> but I cannot be certain because there is too much interacting text.

iterator_traits<T>::difference_type cannot possibly be a deduced context,
especially acting as the return type!

I think that Comeau just has a bug, unless someone can quote
chapter and verse at me to demonstrate otherwise.

---
[ 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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Mon, 5 May 2003 17:37:12 +0000 (UTC)
Raw View
In article <1052142492.54500@master.nyc.kbcfp.com>, Hyman Rosen
<hyrosen@mail.com> writes
>I think that Comeau just has a bug, unless someone can quote
>chapter and verse at me to demonstrate otherwise.

Try 14.8.3/1

The argument deduction succeeds and so the compiler is required to
instantiate the function -- which it cannot.


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Mon, 5 May 2003 17:38:16 +0000 (UTC)
Raw View
In article <1052142100.555128@master.nyc.kbcfp.com>, Hyman Rosen
<hyrosen@mail.com> writes
>James Dennett wrote:
>> Where function1(0) compiles cleanly, but function2(0)
>> does not with either como or g++, and I think they're
>> within their rights to reject it.
>
>I disagree. 14.8.2/4 explicitly says
>    When all template arguments have been deduced,
>    all uses of template parameters in nondeduced
>    contexts are replaced with the corresponding
>    deduced argument values. If the substitution
>    results in an invalid type, as described above,
>    type deduction fails.

I think I agree, but this is becoming increasingly disturbing. In order
to determine if a template function specialisation should be part of the
overload set the compiler must determine that it can indeed be
instantiated. In order to do that it needs to see the definition of the
traits class (well just that in the case in point). It must not simply
add the function template specialisation to the overload set because it
might become the best match when it cannot be instantiated and therefore
should not (according to 14.8.2/4) have been considered.

So how will that work with exported templates? Let me rework my example
a little:

template <typename T>
class x_traits;

template<typename T>
typename x_traits<T>::return_type foo(T, T);

void foo(int, long);

int main(){
        foo(1, 2);
}

Now the compiler chooses foo<int> even though it may later find that it
cannot instantiate it.

--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: hyrosen@mail.com (Hyman Rosen)
Date: Mon, 5 May 2003 19:53:30 +0000 (UTC)
Raw View
Francis Glassborow wrote:
> So how will that work with exported templates? Let me rework my example
> a little:
>
> template <typename T> class x_traits;
> template<typename T> typename x_traits<T>::return_type foo(T, T);
> void foo(int, long);
> int main(){ foo(1, 2); }
>
> Now the compiler chooses foo<int> even though it may later find that it
> cannot instantiate it.

I would expect that you would get a compilation error at the call
to foo(1, 2) because the compiler would need x_traits<int> to be
a complete type, and you failed to supply the definition.

What does this have to do with export? What does export have to do
with incomplete types? Either I'm very confused, or you are!

---
[ 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: hyrosen@mail.com (Hyman Rosen)
Date: Mon, 5 May 2003 20:04:53 +0000 (UTC)
Raw View
Francis Glassborow wrote:
> In article <1052142492.54500@master.nyc.kbcfp.com>, Hyman Rosen
> <hyrosen@mail.com> writes
>
>> I think that Comeau just has a bug, unless someone can quote
>> chapter and verse at me to demonstrate otherwise.
>
> Try 14.8.3/1
>
> The argument deduction succeeds and so the compiler is required to
> instantiate the function -- which it cannot.

14.8.3/1 requires argument deduction *and checking* to succeed.
In this case, checking fails.

---
[ 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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Mon, 5 May 2003 23:06:10 +0000 (UTC)
Raw View
In article <1052163888.254268@master.nyc.kbcfp.com>, Hyman Rosen
<hyrosen@mail.com> writes
>Francis Glassborow wrote:
>> So how will that work with exported templates? Let me rework my example
>> a little:
>>  template <typename T> class x_traits;
>> template<typename T> typename x_traits<T>::return_type foo(T, T);
>> void foo(int, long);
>> int main(){ foo(1, 2); }
>>  Now the compiler chooses foo<int> even though it may later find that
>>it
>> cannot instantiate it.
>
>I would expect that you would get a compilation error at the call
>to foo(1, 2) because the compiler would need x_traits<int> to be
>a complete type, and you failed to supply the definition.

But in fact they do not (or not the ones I have tried.
>
>What does this have to do with export? What does export have to do
>with incomplete types? Either I'm very confused, or you are!

The definition of an exported type does not need to be visible at the
point of use. Now if the return is by pointer or reference (sorry, I
overlooked that requirement) the compiler does not need the type to be
complete. Therefore it has no way to determine if the template can be
instantiated.


--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: hyrosen@mail.com (Hyman Rosen)
Date: Wed, 7 May 2003 04:24:18 +0000 (UTC)
Raw View
Francis Glassborow wrote:
> The definition of an exported type does not need to be visible at the
> point of use.

Says who? Export applies purely to definitions of member functions
and static data memebers. Where do you see that it applies to the
class definition itself? As far as I know, export has nothing to
do with eliminating completeness requirements. Is there a statement
to the contrary in the standard?

> Now if the return is by pointer or reference (sorry, I overlooked
 > that requirement) the compiler does not need the type to be complete.
 > Therefore it has no way to determine if the template can be
> instantiated.

I still don't see how this gets around the requirement that after
argument deduction, all parameter uses in non-deduced contexts have
to be checked for correctness, or type deduction fails.

---
[ 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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Sun, 4 May 2003 04:28:36 +0000 (UTC)
Raw View
 #include <iostream>

 using namespace std;

 typedef int point2d;
 double distance(point2d const & from, point2d const & to);


 int main(){
                 point2d abc(0), xyz(0);
                 cout << distance(abc, xyz);

 }


Look at the above code. Do you think it ought to compile (it doesn't on
at least two well respected compilers)

Is this failure a defect in the Standard? Probably not as I guess those
responsible said what they meant but as sure as hell it isn't what any
ordinary programmer would expect. And yes you can work round by
replacing distance with ::distance but I think that is rather beside the
point.

--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: brangdon@cix.co.uk (Dave Harris)
Date: Sun, 4 May 2003 18:53:50 +0000 (UTC)
Raw View
francis@robinton.demon.co.uk (Francis Glassborow) wrote (abridged):
> Look at the above code. Do you think it ought to compile (it doesn't on
> at least two well respected compilers)

Presumably the problem is that <iostream> brings in a definition of
std::distance which clashes with the user-defined global one.


> Is this failure a defect in the Standard? Probably not as I guess those
> responsible said what they meant but as sure as hell it isn't what any
> ordinary programmer would expect.

In practice my code tends to recursively #include quite a few headers, a
set which changes over time and which is pretty much out of my control.
One of my colleagues may have some inline code which needs <algorithm>. So
I cannot safely assume that <algorithm> is not #included, whatever the
standard says about its own headers.

So in practice this is a non-issue for me.


> And yes you can work round by replacing distance with ::distance but
> I think that is rather beside the point.

In my view the problem is the "using namespace std". Better would be to
use std::cout directly, or else add "using std::cout" somewhere.

Basically, if you use "using namespace std" you probably need to be aware
of every name in that namespace. Or at least accept responsibility for any
clashes that result.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Sun, 4 May 2003 18:54:30 +0000 (UTC)
Raw View
In article <ZXiDxuFeKCt+EwLX@robinton.demon.co.uk>, Francis Glassborow
<francis@robinton.demon.co.uk> writes
>#include <iostream>
>
> using namespace std;
>
> typedef int point2d;
> double distance(point2d const & from, point2d const & to);
>
>
> int main(){
>                 point2d abc(0), xyz(0);
>                 cout << distance(abc, xyz);
>
> }
>
>
>Look at the above code. Do you think it ought to compile (it doesn't on
>at least two well respected compilers)
>
>Is this failure a defect in the Standard? Probably not as I guess those
>responsible said what they meant but as sure as hell it isn't what any
>ordinary programmer would expect. And yes you can work round by
>replacing distance with ::distance but I think that is rather beside the
>point.

Let me follow up on my own post and focus on the main issue, which has
nothing to do with using directives (they only make the problem
manifest)

Consider:

template<typename T>
T foo(T, T);

That declaration can happily coexist with

int foo(int, int);

and we intended such so that template functions can overload with
non-template functions of the same name. However:

template <typename T>
class x_traits;

template<typename T>
x_traits<T>::return_type foo(T, T);

makes  the call foo(1,1);

ill-formed unless x_traits<int> has been defined and provides a type
named return_type. This is irrespective of whether I have declared a
non-template function foo(int, int) [ with any return type]

I think we should choose one of two options:

1) The return type of a function is not used (and therefore is not
checked) until overload resolution selects it.

2) A template function whose return type cannot be instantiated should
be rejected from the overload set.

I prefer option 1. However I am willing to listen to alternatives. What
I would find very difficult to accept is that a template function with a
templated return type should so drastically curtail overloading.





--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: petebecker@acm.org (Pete Becker)
Date: Sun, 4 May 2003 18:54:41 +0000 (UTC)
Raw View
Francis Glassborow wrote:
>
>  #include <iostream>
>
>  using namespace std;
>
>  typedef int point2d;
>  double distance(point2d const & from, point2d const & to);
>
>  int main(){
>                  point2d abc(0), xyz(0);
>                  cout << distance(abc, xyz);
>
>  }
>
> Look at the above code. Do you think it ought to compile (it doesn't on
> at least two well respected compilers)
>
> Is this failure a defect in the Standard? Probably not as I guess those
> responsible said what they meant but as sure as hell it isn't what any
> ordinary programmer would expect. And yes you can work round by
> replacing distance with ::distance but I think that is rather beside the
> point.
>

Thus illustrating why 'using namespace std;' is a bad idea.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

---
[ 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: hyrosen@mail.com (Hyman Rosen)
Date: Sun, 4 May 2003 20:45:42 +0000 (UTC)
Raw View
Francis Glassborow wrote:
> template <typename T> class x_traits;
> template<typename T> x_traits<T>::return_type foo(T, T);
> makes the call foo(1,1); ill-formed unless x_traits<int> has been defined
 > and provides a type named return_type. This is irrespective of whether I
 > have declared a non-template function foo(int, int) [ with any return type]

I don't know why you think this, but you're wrong. Perhaps you are getting
confused because you forgot a 'typename'?
     template<typename T> typename x_traits<T>::return_type foo(T, T);

If you look at 14.8.2/4, you will see it explicitly stated that after
argument deduction, if substitution into non-deduced contexts results
in an illegal type, type deduction fails (which is not an error).

Comeau on-line also compiles the code with no errors.

---
[ 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                       ]