Topic: Is this in fact the standard? If so, whay does ot work this way?


Author: igodardA@TpacbellDO.Tnet ("Ivan Godard")
Date: Tue, 20 Jul 2004 18:14:38 GMT
Raw View
The following is a reported bug on gcc
(http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16610). It prints:
g/x> /home/bangerth/bin/gcc-3.5-pre/bin/c++ x.cc ; ./a.out
array
reference
++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#include    <iostream>

struct Frob1 {
    template<typename T>
    Frob1 (T * const& t) { std::cout << "reference\n"; }

    template<typename T, size_t s>
    Frob1 (T (&t)[s]) { std::cout << "array\n"; }
};

template <typename T>
struct Frob2 {
    Frob2 (T * const& t) { std::cout << "reference\n"; }

    template<size_t s>
    Frob2 (T (&t)[s]) { std::cout << "array\n"; }
};


int main() {
  int ra[10];

  Frob1 f1(ra);
  Frob2<int> f2(ra);
}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
There seems a difference of opinion (or perhaps just confusion) amonst the
gcc maintainers whether this result is in fact standard-conforming. At first
blush it certainly appears that the two calls should bind the same way, but
all available compilers (including non-gcc) give the same result. What does
the standard require? If the compilers are corrrect, should this be
considered a bug in the standard?

Ivan

---
[ 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: do-not-spam-benh@bwsint.com (Ben Hutchings)
Date: Tue, 20 Jul 2004 19:50:51 GMT
Raw View
"Ivan Godard" wrote:
> The following is a reported bug on gcc
> (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16610). It prints:
> g/x> /home/bangerth/bin/gcc-3.5-pre/bin/c++ x.cc ; ./a.out
> array
> reference
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>
> #include    <iostream>
>
> struct Frob1 {
>     template<typename T>
>     Frob1 (T * const& t) { std::cout << "reference\n"; }
>
>     template<typename T, size_t s>
>     Frob1 (T (&t)[s]) { std::cout << "array\n"; }
> };
>
> template <typename T>
> struct Frob2 {
>     Frob2 (T * const& t) { std::cout << "reference\n"; }
>
>     template<size_t s>
>     Frob2 (T (&t)[s]) { std::cout << "array\n"; }
> };
>
>
> int main() {
>   int ra[10];
>
>   Frob1 f1(ra);
>   Frob2<int> f2(ra);
> }
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> There seems a difference of opinion (or perhaps just confusion) amonst the
> gcc maintainers whether this result is in fact standard-conforming. At first
> blush it certainly appears that the two calls should bind the same way, but
> all available compilers (including non-gcc) give the same result. What does
> the standard require?

This appears to be standard-conforming behaviour.

In overload resolution, the viable functions are compared (1) by the
necessary argument conversions, then if neither is better (2) by
whether they are template specialisations (non-template functions are
preferred), then if neither is better and if they are both template
functions (3) by the degree of speciailisations of the templates they
are instantiated from.  There are further tie- breakers which are not
important here; see 13.3.3 for the details.

You might have expected that comparison (1) would resolve both
initialisations to the array-reference constructors.  However table 9
of clause 13 says that array-to-pointer conversion and non-conversion
both rank as "exact match", so neither is preferable to the other.
For Frob1 it is comparison (3) that resolves the initialisation to the
array-reference constructor and for Frob2 it is comparison (2) that
resolves it to the pointer constructor.

> If the compilers are corrrect, should this be considered a bug in
> the standard?

Perhaps non-conversion should be preferred to array-to-pointer and
array-to-function conversion.

---
[ 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: sean@f4.ca (Sean Kelly)
Date: Wed, 21 Jul 2004 14:30:46 GMT
Raw View
igodardA@TpacbellDO.Tnet ("Ivan Godard") wrote in message news:<4yQKc.93829$2O.13693@newssvr29.news.prodigy.com>...
>
>
> template <typename T>
> struct Frob2 {
>     Frob2 (T * const& t) { std::cout << "reference\n"; }
>
>     template<size_t s>
>     Frob2 (T (&t)[s]) { std::cout << "array\n"; }
> };
>
>
> int main() {
>   int ra[10];
>
>   Frob1 f1(ra);
>   Frob2<int> f2(ra);
> }
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

You'll notice that if you change:

template<size_t s>
Frob2 (T (&t)[s]) { std::cout << "array\n"; }

to

Frob2 (T (&t)[10]) { std::cout << "array\n"; }

You will get a compile error about an ambiguous call to an overloaded
function.  What's happening is that in your example the non-template
version is considered more specialized (because it's not a template
function) and thus is chosen as the correct candidate for overload
resolution.  I think this is potentially confusing but I don't have
any issue with the standard as it is written in this regard.  I think
the pertinent bit is in 13.3.3.1:

Given these definitions, a viable function F1 is defined to be a
better function than another viable function F2 if for all arguments
i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
    for some argument j, ICSj(F1) is a better conversion sequence than
ICSj(F2), or, if not that,
    F1 is a non-template function and F2 is a function template
specialization


Sean

---
[ 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: do-not-spam-benh@bwsint.com (Ben Hutchings)
Date: Wed, 21 Jul 2004 18:00:05 GMT
Raw View
I wrote:
<snip>
> In overload resolution, the viable functions are compared (1) by the
> necessary argument conversions, then if neither is better (2) by
> whether they are template specialisations (non-template functions are
> preferred), then if neither is better and if they are both template
> functions (3) by the degree of speciailisations of the templates they
> are instantiated from.

This is perhaps too terse to be clear, but (1)-(3) are meant to
correspond to the first three items in the second list in 13.3.3.

<snip>
> Perhaps non-conversion should be preferred to array-to-pointer and
> array-to-function conversion.

Of course I mean function-to-pointer, not array-to-function.

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