Title
User-defined conversions and built-in operator=
Status
open
Section
12.5 [over.built]
Submitter
Scott Douglas

Created on 2000-11-04.00:00:00 last changed 26 months ago

Messages

Date: 2010-08-15.00:00:00

Additional note (August, 2010):

See issue 507 for a similar example involving comparison operators.

Date: 2010-08-15.00:00:00

Additional note (August, 2010):

See issue 507 for a similar example involving comparison operators.

Date: 2001-04-15.00:00:00

Notes from the 04/01 meeting:

The difference between initialization and assignment is disturbing. On the other hand, promotion is ubiquitous in the language, and this is the beginning of a very slippery slope (as the second report above demonstrates).

Date: 2022-11-20.07:54:16

According to the Standard (although not implemented this way in most implementations), the following code exhibits non-intuitive behavior:

  struct T {
    operator short() const;
    operator int() const;
  };

  short s;

  void f(const T& t) {
    s = t;  // surprisingly calls T::operator int() const
  }

The reason for this choice is 12.5 [over.built] paragraph 18:

For every triple (L, VQ, R), where L is an arithmetic type, VQ is either volatile or empty, and R is a promoted arithmetic type, there exist candidate operator functions of the form

    VQ L& operator=(VQ L&, R);

Because R is a "promoted arithmetic type," the second argument to the built-in assignment operator is int, causing the unexpected choice of conversion function.

Suggested resolution: Provide built-in assignment operators for the unpromoted arithmetic types.

Related to the preceding, but not resolved by the suggested resolution, is the following problem. Given:

    struct T {
	 operator int() const;
	 operator double() const;
    };

I believe the standard requires the following assignment to be ambiguous (even though I expect that would surprise the user):

    double x;
    void f(const T& t) { x = t; }

The problem is that both of these built-in operator=()s exist (12.5 [over.built] paragraph 18):

    double& operator=(double&, int);
    double& operator=(double&, double);

Both are an exact match on the first argument and a user conversion on the second. There is no rule that says one is a better match than the other.

The compilers that I have tried (even in their strictest setting) do not give a peep. I think they are not following the standard. They pick double& operator=(double&, double) and use T::operator double() const.

I hesitate to suggest changes to overload resolution, but a possible resolution might be to introduce a rule that, for built-in operator= only, also considers the conversion sequence from the second to the first type. This would also resolve the earlier question.

It would still leave x += t etc. ambiguous -- which might be the desired behavior and is the current behavior of some compilers.

History
Date User Action Args
2022-02-18 07:47:23adminsetmessages: + msg6662
2013-10-14 00:00:00adminsetstatus: drafting -> open
2010-08-23 00:00:00adminsetmessages: + msg2863
2003-04-25 00:00:00adminsetstatus: open -> drafting
2001-05-20 00:00:00adminsetmessages: + msg511
2000-11-04 00:00:00admincreate