Topic: New rules for user-defined conversions?


Author: Jason Merrill <jason@cygnus.com>
Date: 1997/03/15
Raw View
>>>>> Will Hall <willhall@idt.net> writes:

> The candidates functions are:
> (1) Bob::operator[](unsigned int i) const

> Cand. (1) has no conversion of its right operand `0' (or, in lawerly
> parlance, has a standard conversion (scs) consisting of the Identity
> conversion by itself)

Wrong; it has a standard conversion from int to unsigned int.  So the
second candidate is better for the right operand.

Jason
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: willhall@idt.net (Will Hall)
Date: 1997/03/15
Raw View
Two corrections:

> (2) For the non-const member operator[], arg 1 undergoes a scs (Identity),
> and arg2 undergoes (as per Oliva) the following scs: unsigned int to int.
                                                       ^^^^^^^^^^^^^^^^^^^
                                        [ should read: int to unsigned int ]
>
> (3) For the const member operator[], arg 1 undergoes a scs (Bob& to const
> Bob&), and arg2 undergoes an scs (unsigned int to int).
                                    ^^^^^^^^^^^^^^^^^^^
                     [ should read: int to unsigned int ]

> -Will Hall
> willhall@idt.net

-Will Hall
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1997/03/16
Raw View
Will Hall writes:

> In article <orn2s71lwd.fsf@sunsite.dcc.unicamp.br>, Alexandre Oliva
> <oliva@dcc.unicamp.br> wrote:

>> If you had declared char &Bob::operator[](int i), it would be the best
>> alternative, since no conversions would be required.

> I'm not sure if the above is true or not. In particular:

> Given char& Bob::operator[](int) _and_ const char& Bob::operator[](int)
> const, wouldn't operator<<(ostream&, const char) select the const member
> (which returns a const char&) over the non-const one? Even _without_ the
> new const member function, would operator<<(ostream&, const char) really
> select char& Bob::operator[](int) over const char&
> Bob::operator[](unsigned int) ?

CV-qualifiers that modify the parameter type are deleted; they only
affect the definition of the argument inside the function body, so
operator<<(ostream&,const char) would become
operator<<(ostream&,char), so there's no conflict.

Even if another function that took a const char& as argument were
invoked with the results of the subscription, overload resolution for
the subscript operator would have already taken place, and the type of
the its results would be already determined.

--
Alexandre Oliva
mailto:oliva@dcc.unicamp.br mailto:aoliva@acm.org
Universidade Estadual de Campinas, SP, Brasil
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Nicolas Chapados" <chapados@nortel.ca>
Date: 1997/03/13
Raw View
I'm having problems with the following code fragment.  More specifically,
the new HP C++ compiler (aCC)---which reportedly obeys the latest ANSI
decisions---reports an ambiguous conversion sequence when using operator[].

It's probably my own incompetence, but I could not find in the latest draft
(section 13.3.3.2?) language to rank two disparate user-defined conversion
sequences; like something saying that the operator[]() in a class is better
than first applying operator char*() followed by the built-in
array-indexing operator.

Your comments would be greatly appreciated.


class Bob
{
  char X[100];

public:
  // This gives an error.  There is no error with g++ or HP A.10.24.
  // Comment out line below and everything is okay
  operator const char *() const { return X; }

  const char &operator[]( unsigned int i ) const { return X[i]; }
  char &operator[]( unsigned int i ) { return X[i]; }
};

int main()
{
  Bob bob;

  bob[0] = 'a';
  bob[1] = 'b';
  cout << "Bing: " << bob[0] << endl;

  char x;
  x = bob[0];

  return 0;
}

---
Nicolas Chapados   Home: n.chapados@ieee.ca
Nortel Technology, Montreal, Canada Work: chapados@nortel.ca
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1997/03/14
Raw View
Nicolas Chapados writes:

> I'm having problems with the following code fragment.  More specifically,
> the new HP C++ compiler (aCC)---which reportedly obeys the latest ANSI
> decisions---reports an ambiguous conversion sequence when using operator[].

> It's probably my own incompetence, but I could not find in the latest draft
> (section 13.3.3.2?) language to rank two disparate user-defined conversion
> sequences; like something saying that the operator[]() in a class is better
> than first applying operator char*() followed by the built-in
> array-indexing operator.

Invoking Bob::operator[](unsigned int) would require an implicit
conversion from int(0) to unsigned, and an identity conversion for the
implicit this argument.  OTOH, the user-defined conversion
Bob::operator const char*() const involves a qualification conversion
for the implicit this argument, but an identity conversion for the
indexing operator (subscripting operators on arrays get a ptrdiff_t
argument, which is a signed integral type)

So, the former would be a better choice regarding the implicit this
argument, but the latter would be better regarding the explicit
argument, so there's no best choice, and the construct is ambiguous.

If you had declared Bob::char &operator[](int i), it would be the best
alternative, since no conversions would be required.

--
Alexandre Oliva
mailto:oliva@dcc.unicamp.br mailto:aoliva@acm.org
Universidade Estadual de Campinas, SP, Brasil
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Jason Merrill <jason@cygnus.com>
Date: 1997/03/14
Raw View
>>>>> Nicolas Chapados <chapados@nortel.ca> writes:

> It's probably my own incompetence, but I could not find in the latest draft
> (section 13.3.3.2?) language to rank two disparate user-defined conversion
> sequences; like something saying that the operator[]() in a class is better
> than first applying operator char*() followed by the built-in
> array-indexing operator.

That's because there is no such language.  The expression is ambiguous.

> Your comments would be greatly appreciated.

>   // This gives an error.  There is no error with g++ or HP A.10.24.

g++ 2.7.2 fails to even consider the builtin candidate for your testcase.
2.8.0 with -pedantic will say:

wa.C: In function `int main()':
wa.C:20: ambiguous overload for `Bob &[int]'
wa.C:20: candidates are: operator [](const char *, int) <builtin>
wa.C:13:                 Bob::operator [](unsigned int)
wa.C:12:                 Bob::operator [](unsigned int) const

Without -pedantic, 2.8.0 will resolve ambiguities like this by choosing
the candidate with the lesser maximum rank, and will choose the member
operator for your testcase.

Jason
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: willhall@idt.net (Will Hall)
Date: 1997/03/14
Raw View
In article <199703131705.KAA25292@newncar.ucar.edu.ucar.EDU>, "Nicolas
Chapados" <chapados@nortel.ca> wrote:

> I'm having problems with the following code fragment.  More specifically,
> the new HP C++ compiler (aCC)---which reportedly obeys the latest ANSI
> decisions---reports an ambiguous conversion sequence when using operator[].

> class Bob
> {
>   char X[100];
> public:
>   // This gives an error.  There is no error with g++ or HP A.10.24.
>   // Comment out line below and everything is okay
>   operator const char *() const { return X; }
>   const char &operator[]( unsigned int i ) const { return X[i]; }
>   char &operator[]( unsigned int i ) { return X[i]; }
> };
> int main()
> {
>   Bob bob;
>   bob[0] = 'a';
>   bob[1] = 'b';
>   cout << "Bing: " << bob[0] << endl;
>   char x;
>   x = bob[0];
>   return 0;
> }
> Nicolas Chapados

I guess it probably reports the ambiguity on the line with cout. If so,
the compiler is in error. The heart of the matter is how to resolve
bob[0].

According to 13.3.3[1], a viable func F1 is better than another, F2, if
for each arg i, the implicit conversion sequence (ics) from i to F1's
corresponding param is no worse than the one for F2's corresp param, _and_
for some arg j, the ics to F1's corresp param is better than the ics to
F2's corresp param.

The candidates functions are:
(1) Bob::operator[](unsigned int i) const
(2) Bob::operator const char*() const, together w/ built-in
operator[](const char*, unsigned int) [or however the built-in subscript
operator is designated]

Cand. (1) has no conversion of its right operand `0' (or, in lawerly
parlance, has a standard conversion (scs) consisting of the Identity
conversion by itself), and has a scs of its left operand `bob' from Bob&
to const Bob&.

Cand. (2) has the same scs of its right operand as did cand (1), but its
left operand undergoes a user-defined conversion sequence (ucs), namely,
initial scs: Bob& to const Bob&; user-def'd conv: Bob::operator const
char*() const; second scs: none, i.e., Identity conv).

By 13.3.3.2[2], the scs of candidate (1)'s left arg edges out (i.e., "is
better than") cand. (2)'s udc.

Hence, no ambiguity: the overload resolution mechanism should select
Bob::operator[](unsigned int) const.

-Will Hall
willhall@idt.net
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Gerard Weatherby <gerardw@alum.mit.edu>
Date: 1997/03/15
Raw View
Nicolas Chapados wrote:
>
> I'm having problems with the following code fragment.  More specifically,
> the new HP C++ compiler (aCC)---which reportedly obeys the latest ANSI
> decisions---reports an ambiguous conversion sequence when using operator[].

It's not obvious to me what the error is -- Borland 5.01 compiles it
without complaint.
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: willhall@idt.net (Will Hall)
Date: 1997/03/15
Raw View
In article <orn2s71lwd.fsf@sunsite.dcc.unicamp.br>, Alexandre Oliva
<oliva@dcc.unicamp.br> wrote:

> Nicolas Chapados writes:
>
> > I'm having problems with the following code fragment.

[ fragment synopsis: ]

> > class Bob {
> >   char X[100];
> > public:
> >   operator const char *() const { return X; }
> >   const char &operator[]( unsigned int i ) const { return X[i]; }
> >   char &operator[]( unsigned int i ) { return X[i]; }
> > };
> > int main() {
> >   Bob bob;
> >   bob[0] = 'a';
> >   cout << "Bing: " << bob[0] << endl;
> >   return 0;
> > }

> > ... I could not find in the latest draft
> > (section 13.3.3.2?) language to rank two disparate user-defined conversion
> > sequences; like something saying that the operator[]() in a class is better
> > than first applying operator char*() followed by the built-in
> > array-indexing operator.

> Invoking Bob::operator[](unsigned int) would require an implicit
> conversion from int(0) to unsigned, and an identity conversion for the
> implicit this argument.  OTOH, the user-defined conversion
> Bob::operator const char*() const involves a qualification conversion
> for the implicit this argument, but an identity conversion for the
> indexing operator ...

Oops! I stand corrected (and duly chastened) by Alexandre Oliva's primary
conclusion (above). Still, I offer the following clarifications of his
exposition.

According to 13.3.1.5[2] on "Initialization by conversion function",
Bob::operator const char*() const has nothing to do with the indexing
operator :

:2 The argument list has one argument, which is the  initializer  expres-
:  sion.   [Note:  this  argument  will  be compared against the implicit
:  object parameter of the conversion functions.  ]

So its lone arg is bob, which Oliva rightly point out will undergo a
qualification conversion (Bob& to const Bob&), but _only_ in the context
of consideration of operator const char* as a user-defined-conversion for
the left operand of builtin operator[](const char*, int).

According to 13.3[1]:

:1 Overload resolution is a mechanism for selecting the best function  to
:  call  given  a list of expressions that are to be the arguments of the
         ^^^^^
:  call and a set of candidate functions that can be called based on  the
:  context of the call.

This would appear to imply that, for our example, the competing candidates
each take the same list of two given args (bob and 0) and are (as per
Jason Merrill's g++ 2.8.0 -pedantic output):

%wa.C:20: candidates are: operator [](const char *, int) <builtin>
%wa.C:13:                 Bob::operator [](unsigned int)
%wa.C:12:                 Bob::operator [](unsigned int) const

(1) For the builtin, arg 1 (bob) undergoes a user-defined-conversion
sequence (Bob& to const Bob&; to const char*; Identity), and arg 2 (0)
undergoes a standard-conversion-sequence (Identity).

(2) For the non-const member operator[], arg 1 undergoes a scs (Identity),
and arg2 undergoes (as per Oliva) the following scs: unsigned int to int.

(3) For the const member operator[], arg 1 undergoes a scs (Bob& to const
Bob&), and arg2 undergoes an scs (unsigned int to int).

> So, the former would be a better choice regarding the implicit this
> argument, but the latter would be better regarding the explicit
> argument, so there's no best choice, and the construct is ambiguous.

More accurately, non-const member operator[] would be a better choice
w.r.t. the first arg (scs on implicit object param instead of ucs), but
builtin operator[] would be better w.r.t. the second arg (Identity scs
instead of `int to unsigned int'), so there's no best choice; hence, it's
ambiguous.
[Q. Does anyone agree/disagree?]

> If you had declared Bob::char &operator[](int i), it would be the best
> alternative, since no conversions would be required.

I'm not sure if the above is true or not. In particular:

Given char& Bob::operator[](int) _and_ const char& Bob::operator[](int)
const, wouldn't operator<<(ostream&, const char) select the const member
(which returns a const char&) over the non-const one? Even _without_ the
new const member function, would operator<<(ostream&, const char) really
select char& Bob::operator[](int) over const char&
Bob::operator[](unsigned int) ?

-Will Hall
willhall@idt.net
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]