This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 114a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-04-18


1831. Explicitly vs implicitly deleted move constructors

Section: 11.4.5.3  [class.copy.ctor]     Status: NAD     Submitter: Vinny Romano     Date: 2014-01-13

According to 11.4.5.3 [class.copy.ctor] paragraph 11,

A defaulted move constructor that is defined as deleted is ignored by overload resolution (12.2 [over.match], 12.3 [over.over]). [Note: A deleted move constructor would otherwise interfere with initialization from an rvalue which can use the copy constructor instead. —end note]

Limiting this provision to defaulted move constructors introduces an unfortunate distinction between implicitly and explicitly deleted move constructors. For example, given

  #include <iostream>
  #include <memory>
  using namespace std;

  struct Expl {
    Expl() = default;
    Expl(const Expl &) {
      cout << " Expl(const Expl &)" << endl;
   }
   Expl(Expl &&) = delete;
  };

  struct Impl : Expl {
    Impl() = default;
    Impl(const Impl &) {
      cout << " Impl(const Impl &)" << endl;
    }
    Impl(Impl &&) = default;
  };

  struct Moveable {
    Moveable() { }
    Moveable(const Moveable &) {
      cout << " Moveable(const Moveable &)" << endl;
    }
    Moveable(Moveable &&) {
      cout << " Moveable(Moveable &&)" << endl;
    }
  };

  template<typename T> struct Container {
    Moveable moveable[2];
    T t;
  };

  int main() {
    cout << "Expl:" << endl;
    Container<Expl> c1(move(Container<Expl>()));
    cout << "Impl:" << endl;
    Container<Impl> c2(move(Container<Impl>()));
  }

The output of this program is

  Expl:
   Moveable(const Moveable &)
   Moveable(const Moveable &)
   Expl(const Expl &)
  Impl:
   Moveable(Moveable &&)
   Moveable(Moveable &&)
   Impl(const Impl &)

Should the specification be changed to allow overload resolution to ignore all deleted move constructors instead of only the defaulted ones?

From one perspective, at least, the principal reason to delete a move constructor explicitly is to elicit an error if a move is attempted, and such a change would violate that intent. On the other hand, minimizing the difference between explicit default and implicit default seems like an important goal.

Rationale (February, 2014):

The specification is as intended.