Явный конструктор копирования и std::sort

При сортировке контейнера объектов с явным ctor копирования я получаю ошибки компилятора (из g++ 4.8.2 и clang++ 3.4, оба в режиме -std=c++11), которые я не понимаю. Я создал простой пример, чтобы продемонстрировать проблему

class A {
public:
  explicit A(int i): m_i(i) {};
  explicit A(const A& other): m_i(other.m_i) {};
  int i() const {return m_i;};
private:
  int m_i;
};

bool is_less(const A& a, const A& b) {
  return a.i() < b.i();
}

int main(int, char*[]) {
  std::vector<A> objects;
  objects.push_back(A(3));
  objects.push_back(A(5));
  objects.push_back(A(-1));

  std::cout << is_less(objects[1], objects[2]);
  std::sort(objects.begin(), objects.end(), is_less);

  for (auto& a: objects) {
    std::cout << a.i() << " ";
  }
  std::cout << std::endl;
}

Это терпит неудачу с

error: 
  no matching constructor for initialization of '_ValueType' (aka 'A')

в clang++ и с

error: no matching function for call to ‘A::A(std::remove_reference<A&>::type)

в г++. Код компилируется и работает нормально, если конструктор копирования не является явным (но я хочу обеспечить, чтобы в качестве параметров и возвращаемых значений могли использоваться только ссылки на мои объекты). Код также компилируется после удаления вызова std::sort (поэтому is_less(objects[1], objects[2]) не проблема). Следовательно, мой вопрос заключается в том, что делает std::sort при вызове функции сравнения, которая приводит к сбою компиляции этого кода, и как это исправить.

После долгих исследований единственный вопрос, который приблизился к моей проблеме, - это При инициализации копирования вызов конструктора копирования является явным или неявным? который связан с ошибкой в ​​gcc. Однако clang показывает такое же поведение, поэтому мне очень хотелось бы понять, что происходит.


person Gerald Senarclens de Grancy    schedule 27.08.2014    source источник
comment
Только сумасшедшие делают конструкторы копирования explicit, такие типы не являются CopyConstructible   -  person Jonathan Wakely    schedule 27.08.2014


Ответы (1)


std::sort требует, чтобы тип элемента был MoveConstructible.

В требованиях к MoveConstructible указано, что выражение T u = rv; должно быть допустимым. Однако это выражение выполняет инициализацию копирования и требует наличия неявного конструктора копирования или перемещения.

В этом случае конструктор копирования является явным, и его объявление означает отсутствие неявно объявленного конструктора перемещения. Следовательно, выражение неверно, а класс A не является MoveConstructible.

person interjay    schedule 27.08.2014
comment
Что делает выражение недействительным, так это не только то, что конструктор копирования является явным, но и то, что в качестве побочного эффекта простого наличия конструктора копирования в первую очередь отключается конструктор перемещения. С конструктором перемещения и оператором присваивания перемещения это работает, даже если конструктор копирования все еще является явным. - person ; 27.08.2014