Topic: CPP Experts: Why Ambiguous?


Author: wlcna@nospam.com ("wlcna")
Date: Fri, 13 Sep 2002 16:15:17 +0000 (UTC)
Raw View
"Alf P. Steinbach" <alf_p_steinbach@yahoo.no.invalid> wrote in message
news:3d7e64a5.250979796@news.online.no...
> [snip]
> Having identified the rules that so make f(int) a better match
> than f(char), and f(long) not a better match than f(char),
> shouldn't something be done about that?
>
> I can't imagine that anyone finds this intuitive, but I can
> imagine that there is some obscure yet well-founded tecnical
> reason (not for the result but) for the current rules.
>

Thanks for your interest and responses.  It seems to me it is a minor defect
in the language, at least if one considers minutiae at this level
significant.  The workaround as you noted (and I as well in my own prior
follow-up to the earlier responder) is to define an overload for all the
basic integer types such that you always get an exact match.

I think there may be a historical reason for the indifference to signedness,
either that or it was just done to keep the compiler vendors happy and
simple.  Anyone know?

FWIW, the reason this came up for me was in a simple print routine that
originally was not overloaded, just defined once with a large, signed
integer type.  I had a bug due to unwanted sign-extension with an unsigned
input.  I believe the type of the argument was from a typedef which may have
been pretty far from my code.  So I'd point out that I didn't easily know
whether it was signed or not, and I'd note that in alot of cases this may be
true when using lots of libraries and such (e.g. who knows off the top of
their head if std::string::size_type is signed or not).  So THE IDEA of my
overload on unsigned was to allow the compiler to keep track of what's
signed and what's not and then I'd get sign extension automatically when it
was desirable and would not get it when it wasn't.

But alas, for once, C++ thwarted me!  I love C++ too.  I give the above
description because I think it's useful to know the exact activity that the
language is hindering.

Anyway, there's the workaround of defining an overload for all the basic
integer types, which would still allow this nice effect.  If I went back to
this code with time to spare, I'd probably do that.  In the meantime, I
think I just went for the cast (casting unsigned smaller argument to
unsigned larger type argument, then compiler does conversion of unsigned
larger type to signed larger type invisibly).

C++ here is helping you shoot yourself in the foot and doing something that
it seems to me leads to more casting.  And isn't C++ supposed to help you
get rid of casting?

I'd love to hear about WHY things are this way.  I already know HOW things
are and I laid that out in detail in my second post (a day prior to all the
posts in this sub-thread), but I'm curious WHY such a strange rule where
information destroying and sign-destroying conversions are considered
exactly the same for overloading.

I read the D&E on this and it seems to indicate historical and compiler
simplicity issues but doesn't quite penetrate the exact issues on this very
commonly encountered programming topic, and perhaps I'd even call it a C/C++
programming bugaboo.

---
[ 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: rmaddox@isicns.com (Randy Maddox)
Date: Tue, 10 Sep 2002 15:44:34 +0000 (UTC)
Raw View
alf_p_steinbach@yahoo.no.invalid (Alf P. Steinbach) wrote in message news:<3d7ad8c5.18567062@news.online.no>...
> On Sun, 08 Sep 2002 03:32:03 GMT, "wlcna" <wlcna@nospam.com> wrote:
>
> >Try the code below.  Why do the implicit conversions on the lines noted give
> >C2668 errors (Visual C, but GCC I also tried, and it gives similar)?
> >
> >My thought was that the standard says if there is an unambiguously better
> >conversion available then it should be used.  It seems to me the char->short
> >is unambiguously better than char->unsigned short.  Why isn't that correct?

See subclause 13.3.  Your asssumption here is not correct due to the
fact that both of the conversion sequences you mention are equivalent
in that they are of the same length, i.e., each involves a single
conversion.  Thus, to the compiler neither is better and the call is
ambiguous.

> >Also, some might say that whether char is signed or unsigned is
> >implementation dependent (I'm quite sure I'm right on that though obviously
> >it is in practice almost always defined as signed), but then how to explain
> >the SAME ERROR with the variable specifically declared unsigned??  (As
> >another note on this issue, I got the same error even if I change the
> >myShortFun( short ) to myShortFun( signed short ), making explicit what it
> >is intended to be.
> >
> >I'd appreciate pointers to info on this, I've done some searches and not
> >come up with much that's definitive.
>
> Uh, [lots of expletives], at first I thought this was trivial but then
> found very little clear information.
>
> What happens is, as far I can see, first that there is no exact
> match.  If there were it would have taken precedence.

Absolutely correct.  :-)

>
> Then, there is no automatic *promotion* from char to unsigned.  The
> reason is that $4.5 only defines promotions to int and unsigned int,
> except for wchar_t (which can be promoted to long or unsigned long).
>
> (Note in parenthesis: so called arithmetic conversions, when you
> have integral values as operands to e.g. multiplication, don't
> apply here  --  although they're often thought of as promotions.)
>
> What then? Well, we're left in *conversion-land*.  And $4.7, which
> defines integral conversions, doesn't rank them in any way depending
> on the size of the types.  Provided my thinking is correct, then
> it's at this point the compiler gives up; it simply doesn't consider
> and isn't allowed to consider whether the integral conversion could
> potentially by lossy or not.
>
> Hence, we're left in the absurd situation where a "short" actual
> argument would be equally well matched to a "char" as to a "long"
> formal parameter, giving the same (idiotic!) result.  Let's see:
>
>
>     void f( char ){}
>     void f( long ){}
>
>     int main()
>     {
>         short x;
>
>         f( x );
>         return 0;
>     }
>
>
> What does Visual C++ 7.0 have to say about that, I wonder?
>
>
>     C:\temp> cl /nologo x.cpp
>     x.cpp
>     x.cpp(8) : error C2668: 'f' : ambiguous call to overloaded
>     function
>             x.cpp(2): could be 'void f(long)'
>             x.cpp(1): or       'void f(char)'
>             while trying to match the argument list '(short)'
>
>     C:\temp> _
>
>

Same issue here.  Both conversion sequences are of length one and thus
neither is better than the other.

Randy.

> I think you're really on to something!  Try posting this in
> [comp.std.c++], for consideration in C++0x.  On further
> thought, I do it now; follow-up set to [comp.std.c++].
>
> Cheers,
>
> - Alf

---
[ 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: alf_p_steinbach@yahoo.no.invalid (Alf P. Steinbach)
Date: Wed, 11 Sep 2002 02:56:21 +0000 (UTC)
Raw View
On Tue, 10 Sep 2002 15:44:34 +0000 (UTC), rmaddox@isicns.com (Randy
Maddox) wrote:

>alf_p_steinbach@yahoo.no.invalid (Alf P. Steinbach) wrote in message news:<3d7ad8c5.18567062@news.online.no>...
>> On Sun, 08 Sep 2002 03:32:03 GMT, "wlcna" <wlcna@nospam.com> wrote:
>>
>> >Try the code below.  Why do the implicit conversions on the lines noted give
>> >C2668 errors (Visual C, but GCC I also tried, and it gives similar)?
>> >
>> >My thought was that the standard says if there is an unambiguously better
>> >conversion available then it should be used.  It seems to me the char->short
>> >is unambiguously better than char->unsigned short.  Why isn't that correct?
>
>See subclause 13.3.  Your asssumption here is not correct due to the
>fact that both of the conversion sequences you mention are equivalent
>in that they are of the same length, i.e., each involves a single
>conversion.  Thus, to the compiler neither is better and the call is
>ambiguous.
>
>> >Also, some might say that whether char is signed or unsigned is
>> >implementation dependent (I'm quite sure I'm right on that though obviously
>> >it is in practice almost always defined as signed), but then how to explain
>> >the SAME ERROR with the variable specifically declared unsigned??  (As
>> >another note on this issue, I got the same error even if I change the
>> >myShortFun( short ) to myShortFun( signed short ), making explicit what it
>> >is intended to be.
>> >
>> >I'd appreciate pointers to info on this, I've done some searches and not
>> >come up with much that's definitive.
>>
>> Uh, [lots of expletives], at first I thought this was trivial but then
>> found very little clear information.
>>
>> What happens is, as far I can see, first that there is no exact
>> match.  If there were it would have taken precedence.
>
>Absolutely correct.  :-)
>
>>
>> Then, there is no automatic *promotion* from char to unsigned.  The
>> reason is that $4.5 only defines promotions to int and unsigned int,
>> except for wchar_t (which can be promoted to long or unsigned long).
>>
>> (Note in parenthesis: so called arithmetic conversions, when you
>> have integral values as operands to e.g. multiplication, don't
>> apply here  --  although they're often thought of as promotions.)
>>
>> What then? Well, we're left in *conversion-land*.  And $4.7, which
>> defines integral conversions, doesn't rank them in any way depending
>> on the size of the types.  Provided my thinking is correct, then
>> it's at this point the compiler gives up; it simply doesn't consider
>> and isn't allowed to consider whether the integral conversion could
>> potentially by lossy or not.
>>
>> Hence, we're left in the absurd situation where a "short" actual
>> argument would be equally well matched to a "char" as to a "long"
>> formal parameter, giving the same (idiotic!) result.  Let's see:
>>
>>
>>     void f( char ){}
>>     void f( long ){}
>>
>>     int main()
>>     {
>>         short x;
>>
>>         f( x );
>>         return 0;
>>     }
>>
>>
>> What does Visual C++ 7.0 have to say about that, I wonder?
>>
>>
>>     C:\temp> cl /nologo x.cpp
>>     x.cpp
>>     x.cpp(8) : error C2668: 'f' : ambiguous call to overloaded
>>     function
>>             x.cpp(2): could be 'void f(long)'
>>             x.cpp(1): or       'void f(char)'
>>             while trying to match the argument list '(short)'
>>
>>     C:\temp> _
>>
>>
>
>Same issue here.  Both conversion sequences are of length one and thus
>neither is better than the other.

Yes, that's the issue.

If instead of

  f(char){}
  f(long){}

we had

  f(char){}
  f(int){}

the latter *would* be a better match  --  by the current rules  --
because int is an integral promotion of short, while long isn't.

Having identified the rules that so make f(int) a better match
than f(char), and f(long) not a better match than f(char),
shouldn't something be done about that?

I can't imagine that anyone finds this intuitive, but I can
imagine that there is some obscure yet well-founded tecnical
reason (not for the result but) for the current rules.

Cheers,

- Alf

---
[ 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: alf_p_steinbach@yahoo.no.invalid (Alf P. Steinbach)
Date: Mon, 9 Sep 2002 19:01:59 +0000 (UTC)
Raw View
On Sun, 08 Sep 2002 03:32:03 GMT, "wlcna" <wlcna@nospam.com> wrote:

>Try the code below.  Why do the implicit conversions on the lines noted give
>C2668 errors (Visual C, but GCC I also tried, and it gives similar)?
>
>My thought was that the standard says if there is an unambiguously better
>conversion available then it should be used.  It seems to me the char->short
>is unambiguously better than char->unsigned short.  Why isn't that correct?
>Also, some might say that whether char is signed or unsigned is
>implementation dependent (I'm quite sure I'm right on that though obviously
>it is in practice almost always defined as signed), but then how to explain
>the SAME ERROR with the variable specifically declared unsigned??  (As
>another note on this issue, I got the same error even if I change the
>myShortFun( short ) to myShortFun( signed short ), making explicit what it
>is intended to be.
>
>I'd appreciate pointers to info on this, I've done some searches and not
>come up with much that's definitive.

Uh, [lots of expletives], at first I thought this was trivial but then
found very little clear information.

What happens is, as far I can see, first that there is no exact
match.  If there were it would have taken precedence.

Then, there is no automatic *promotion* from char to unsigned.  The
reason is that $4.5 only defines promotions to int and unsigned int,
except for wchar_t (which can be promoted to long or unsigned long).

(Note in parenthesis: so called arithmetic conversions, when you
have integral values as operands to e.g. multiplication, don't
apply here  --  although they're often thought of as promotions.)

What then? Well, we're left in *conversion-land*.  And $4.7, which
defines integral conversions, doesn't rank them in any way depending
on the size of the types.  Provided my thinking is correct, then
it's at this point the compiler gives up; it simply doesn't consider
and isn't allowed to consider whether the integral conversion could
potentially by lossy or not.

Hence, we're left in the absurd situation where a "short" actual
argument would be equally well matched to a "char" as to a "long"
formal parameter, giving the same (idiotic!) result.  Let's see:


    void f( char ){}
    void f( long ){}

    int main()
    {
        short x;

        f( x );
        return 0;
    }


What does Visual C++ 7.0 have to say about that, I wonder?


    C:\temp> cl /nologo x.cpp
    x.cpp
    x.cpp(8) : error C2668: 'f' : ambiguous call to overloaded
    function
            x.cpp(2): could be 'void f(long)'
            x.cpp(1): or       'void f(char)'
            while trying to match the argument list '(short)'

    C:\temp> _


I think you're really on to something!  Try posting this in
[comp.std.c++], for consideration in C++0x.  On further
thought, I do it now; follow-up set to [comp.std.c++].

Cheers,

- Alf

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