From 2903791161205448488
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: f78e5,7a70a984c05833de
X-Google-Attributes: gidf78e5,public
X-Google-ArrivalTime: 1991-07-08 23:07:51 PST
Path: gmdzi!unido!mcsun!uunet!microsoft!jangr
From: jangr@microsoft.UUCP (Jan GRAY)
Newsgroups: comp.std.c++
Subject: Re: Overloading Resolution
Keywords: Overloading Resolution, Argument Matching, Compiler Bugs
Message-ID: <73348@microsoft.UUCP>
Date: 4 Jul 91 02:56:48 GMT
References: <1991Jun26.140508.19662@csi.uottawa.ca>
Reply-To: jangr@microsoft.UUCP (Jan GRAY)
Organization: Microsoft Corp., Redmond WA
Lines: 175

In article <1991Jun26.140508.19662@csi.uottawa.ca> hitz@csi.uottawa.ca (Martin Hitz) writes:
>In the course of testing my understanding of the rules for argument matching
>given in section 13.2 in the ARM, I tried to predict the outcome of the
>program given below. In order to verify my conclusions, I tried the
>program with 4 different compilers (GNU g++, Sun's cfront, Zortech, and
>Borland C++). As the results have been somewhat arbitrary, I'd like to
>get your comments on who's right:


OK.  Here goes...

>#include <stream.h>
>
>void f (const double &, double, void *)         { cout << 1; }
>void f (double &, int, const char * = 0)        { cout << 2; }
>void f (int)                                    { cout << 3; }
>void f (long, int = 0)                          { cout << 4; }
>
>main ()
>{
>        double b;
>        const double pi = 3.14;
>        
>                        //      Z       g++     cfront  BC++
>                        //---------------------------------------


>        f(1.1, 1, f);   //      1       err     err     1

    Should be error.

    Because there are three actuals, only f[1] and f[2] could be candidates.
    However, there is no conversion from the actual expression "f" (overloaded)
    to either of "void *" or "const char *".

    13.2: "...A call of a given function name chooses, from among all functions
    by that name that are in scope and for which a set of conversions exists so
    that the function could possibly be called ..."

    For this set of actuals, no function could possibly be called.



>        f(1, 1, "Y");   //      err     err     err     2

    Everybody's wrong.  The right answer is f[1]!

    Again, there are three actuals so only f[1] or f[2] could be candidates.
    However, f[2] could not possibly be called because it is illegal in
    C++ 2.1 to initialize a "double &" formal parameter from an actual "1".
    See 8.4.3: "A reference to a plain T can be initialized only with a
    plain T."  The actual "1" has type int which is not a plain double.
    (Perhaps your cfront is pre 2.1?)

    Once again,
    13.2: "...A call of a given function name chooses, from among all functions
    by that name that are in scope and for which a set of conversions exists so
    that the function could possibly be called ..."

    Here the only function that could possibly be called is f[1].
    That's the one which should be called.



>        f(3, 1.1, 0);   //      err     err     1       err

    f[1] should be called.

    Again, there are three actuals so only f[1] or f[2] could be candidates.
    By the explanation above, f[2] is not a candidate.
    Since a set of conversions exist which permits f[1] to be called, it
    should be called, just as explained in the previous case.



>        f(1.1, 3, (void*)0);//  err     1       1       err

    f[1] should be called.

    Again, there are three actuals so only f[1] or f[2] could be candidates.
    Conversions exist to call f[1] so it is a candidate.
    However, f[2] cannot be called because there is no conversion
    from "void *" to "const char *" in C++.  Thus f[1] is the only
    candidate thus, by the first paragraph of 13.2 it should be called.



>        f(1, 1);        //      err     4       4       4

    f[4] should be called.  Only f[4] has the right number of formals
    and conversions exist to call it.  (f[2] can't be called, there's
    no conversion from 1 to "double&".)



>        f(pi, pi, "Y"); //      1       1       1       err

    Error, ambiguous.  Both f[1] and f[2] have the right number of
    formals and the actuals can be converted to the formals for both
    f[1] and f[2].  Finally, we have to start disambiguating by
    considering costs of conversions.

    Parameter 1:
        f[1]:   pi      -> double&          exact/match with trivial convs
        f[2]:   pi      -> const double&    exact/match with trivial convs
    Parameter 1 best match set: { f[1], f[2] }.

    Parameter 2:
        f[1]:   pi      -> double           exact/match with trivial convs
        f[2]:   pi      -> int              match with standard conversions
    Parameter 2 best match set: { f[1] }.

    Parameter 3:
        f[1]:   "Y"     -> void *           match with standard conversions
        f[2]:   "Y"     -> const char *     exact/match with trivial convs
    ("Y" is of type array of char;
     this is trivially promoted to pointer to char
     this is trivially promoted to pointer to const char)
    Parameter 3 best match set: { f[2] }.
    
    Intersection of best match sets: { f[1], f[2] } ^ { f[1] } ^ { f[2] } = nil
    Since intersection is nil (empty), call is ambiguous.



>        f(0L);          //      4       3       4       4

    f[4] should be called.  The two candidates f[3] and f[4] have appropriate
    numbers and types of arguments.  Disambiguate by cost of conversions:

    Parameter 1:
        f[3]:   0L      -> int              match with standard conversions
        f[4]:   0L      -> long             exact/match with trivial convs
    Parameter 1  best match set: { f[4] }.

    Thus f[4] should be called.



>        f(0L, 'a');     //      err     4       4       4

    f[4] should be called.  The two candidates with 2 arguments are
    f[2] and f[4].  However, there is no conversion from 0L to "double&"
    (see 8.4.3 again).  Thus the only function with right numbers of
    arguments and with conversions from actuals to formals is f[4].


>        f(pi);          //      err     3       err     err

    Error, ambiguous.

    Two possible functions, f[3] and f[4], both of which have right
    numbers of arguments, and conversions exist from pi to their
    formal types.  Disambiguate by cost of conversions:

    Parameter 1:
        f[3]:   pi      -> int              match with standard conversions
        f[4]:   pi      -> long             match with standard conversions
    Parameter 1 best match set: { f[3], f[4] }.

    Intersection of best match sets for this (one) argument yields
    { f[3], f[4] }.  13.2: "Unless this intersection has exactly one member,
    the call is illegal.



The current overloaded function disambiguation rules are anything but
intuitive!  Just wait til X3J16 tries to specify the rules for
disambiguating amongst overloaded operator functions and builtin
operator functions on objects when user defined conversion
functions are applied...

Cheers.

Jan Gray  jangr@microsoft.com  Microsoft Corp., Redmond, WA  206-882-8080


