Why doesn't std::optional allow move assignment for "move construct and copy assign only" types?
Asked Answered
S

1

5

The standard mandates that the move assignment operator of optional ...

constexpr optional& operator=( optional&& other )

[...] shall not participate in overload resolution unless is_move_constructible_v<T> is true and is_move_assignable_v<T> is true.

The assignment of an optional value lhs = rhs; does either

  • destroy lhs (if bool(lhs) && !bool(rhs))
  • construction lhs from rhs (if !bool(lhs) && bool(rhs)) or
  • assign rhs to lhs (if bool(lhs) && bool(rhs)).

Thus, it would have been an option to have two sets of preconditions for move assignment of optional:

  1. is_move_constructible_v<T> && is_move_assignable_v<T>
  2. is_move_constructible_v<T> && is_copy_assignable_v<T>

Where the second form could use copy assignment if bool(lhs) && bool(rhs) but move construction if !bool(lhs) && bool(rhs).

I see an admittedly rather artificial issue with the current set of preconditions with respect to the following two classes of types:

  1. A type which is not move assignable but copy assignable, move constructible and copy constructible can not benefit from move construction on assignment, eventhough construction is part of the assignment operation. The optional copy assignment operator will be selected and copy construct or copy assign the value.

  2. A type which is neither copy constructible nor move assignable but move constructible and copy assignable cannot be assigned at all.

Is this something that has been considered during the standardization process for optional or is there any rationale why it has not been considered or has been waived?

(Disclaimer: I know that is_move_assignable is usually true if is_copy_assignable is true unless the move assignment operator is explicitly deleted.)

Sello answered 18/3, 2019 at 20:49 Comment(10)
is_move_constructible_v<T> && is_move_assignable_v<T> == is_move_constructible_v<T> && is_copy_assignable_v<T> so it's not needed. As show here an implicitly deleted move assignment operator is still move assignable as long as the copy assignment operator is not deleted.Heteropterous
@NathanOliver: That's what my disclaimer says. Explicitly deleting the move assignment operator makes is_move_assignable<T> false, regardless of the presence of copy assignment. There is a reason I wrote that the problem is "rather artificial".Sello
Why would you explicitly delete the move operations but allow the copy?Heteropterous
If the problem is really so artificial, as you admit, then it doesn't make sense for the standard to increase the effort required of library implementers by forcing them to sometimes use the copy assignment operator instead of the move assignment operator. Or, for that matter, to complicate the standard itself by codifying this requirement.Trisyllable
If you have a type that is copy-{construct,assign}able but not move-{construct,assign}able, you're doing something very strange, and I'm not sure that it's worth complicating the library to support such a thing.Mariannemariano
Also for the library concepts, CopyConstructible subsumes MoveConstructible.Mariannemariano
As a general rule, the library could not care less about copyable-but-not-movable abominations.Speed
@T.C.: Technically, the suggested issue is worse than that; it's move-constructible, but not move-assignable.Tisman
As a general rule, at least one library implementer thinks such types should be burnt and then thrown in the sea. And he's absolutely certain it's not worth complicating the library to support such things. Just throw them in the sea and forget about them.Washable
@JonathanWakely : Let me agree but also add that I think such types might actually exist (either by mistake or ignorance).Sello
F
6

You should consider using std::optional::emplace for move-constructible types (second case)

Fledge answered 14/7, 2019 at 22:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.