Enlico
Enlico

Reputation: 28416

Is the use of conversion operator forbidden for the lhs of user-defined operator= for user-defined types? If so, what part of the standars forbids it?

Take a simple class wrapping an int,

struct Foo {
    int x;
} f;

and a class that holds a Foo and that can be converted to it,

struct Bar {
    Foo f;
    operator Foo&() {
        return f;
    }
    operator Foo const&() const {
        return f;
    }
    Bar& operator=(Bar const&) = default;
} b;

What part of the standard, if any, makes this invalid

b = f;

instead of being equivalent to this?

static_cast<Foo&>(b) = f;

(I'm not saying it should, nor that it would be normal, expected or anything like that.)

Here I read that

For the built-in assignment operators, conversions of the left operand are restricted as follows:

  • [...]
  • no user-defined conversions are applied to the left operand to achieve a type match with the left-most parameter of a built-in candidate.

For all other operators, no such restrictions apply.

So am I misunderstanding the meaning of "built-in assignment operator" and the = in b = f is the built-in = to which that restriction applies?

Or is that = not the bult-in and so that restriction does not apply but the code is flawed for other reasons?

Upvotes: 1

Views: 98

Answers (2)

Barry
Barry

Reputation: 303087

Paragraph 3 there describes the candidate set:

  • For a unary operator @ with an operand of type cv1 T1, and for a binary operator @ with a left operand of type cv1 T1 and a right operand of type cv2 T2, four sets of candidate functions, designated member candidates, non-member candidates, built-in candidates, and rewritten candidates, are constructed as follows:
    1. If T1 is a complete class type or a class currently being defined, the set of member candidates is the result of a search for operator@ in the scope of T1; otherwise, the set of member candidates is empty.
    2. For the operators =, [], or ->, the set of non-member candidates is empty; otherwise [...]

So for b = f, our member candidates are b.operator=(f) and we have no non-member candidates.

The paragraph that you cited talks about when the built-in candidates are viable, but built-in are those provided by the language (in [over.built]) - those could apply if your type is convertible to something like int&. Those aren't relevant here.

But in this case, b is convertible to Foo&, and there's no mechanism here to consider Foo::operator= as a candidate. We only have the member candidates to consider, and only our own (Bar's) members - not arbitrary other types' members.

Upvotes: 4

Ben Voigt
Ben Voigt

Reputation: 283684

The copy assignment operator you are considering is not a "built in" operator, but conversion of operands to overloaded operators are also restricted, as follows:

when converting to the implicit object parameter or when converting to the left operand of an assignment operation only standard conversion sequences are allowed.

https://eel.is/c++draft/over.best.ics#general-9

which is also mentioned in this note

Note 1: Because only standard conversion sequences are considered when converting to the left operand of an assignment operation ([over.best.ics]), an expression x = y with a subexpression x of class type is always interpreted as x.operator=(y).

https://eel.is/c++draft/over.oper#over.ass-note-1

Upvotes: 2

Related Questions