Копирование параметра вызывает удаленный конструктор, когда этот конструктор не должен вызываться
#include <memory>
template <typename T>
class Wrapper {
public:
Wrapper() = delete;
Wrapper(const Wrapper&) = delete;
Wrapper(Wrapper&&) = delete;
~Wrapper() = default;
Wrapper(const T&) = delete;
Wrapper(T&& in) : instance{std::move(in)} {}
T instance;
};
void foo(Wrapper<std::shared_ptr<int>>) {}
int main() {
auto ptr = std::make_shared<int>(1);
foo(std::move(ptr));
}
Это работало в C++17, поэтому я никогда не задумывался над этим, но почему этот код пытается вызвать конструктор перемещения в C++14? Разве это не должно быть построено на месте в аргументе функции? Кажется, это не проблема с C++17, но не компилируется с C++14.
Единственный обходной путь, который я вижу, это сделать foo
Параметр rvalue, но есть ли что-то, что я могу сделать, чтобы сделать эту работу без параметра в foo
значение в C++14?
Моей первой мыслью было бы, что временный объект должен быть конструктором для передачи в функцию, но что еще более удивительно, это то, что даже при -fno-elide-constructors
и удаление конструкторов перемещения и конструкторов копирования, которые, кажется, не называются! Это ошибка в gcc и clang?
См. https://wandbox.org/permlink/f6sa5Rm3NxZLy5P1 об ошибке и просмотрите странное поведение https://wandbox.org/permlink/Kh6CG4OVbUAjvEZz
1 ответ
Когда вы звоните foo(std::move(ptr));
Вы не даете это Wrapper<std::shared_ptr<int>>
, Таким образом, компилятор генерирует временный и использует его для создания foo
параметр. Теперь это может быть исключено, и мы можем непосредственно построить Wrapper<std::shared_ptr<int>>
но конструктор перемещения / копирования все еще должен быть доступен, даже если он никогда не вызывается.
С C++17 этого больше не происходит. Мы гарантировали исключение копирования, что означает, что временные данные никогда не материализуются, а параметр создается напрямую.