код:
#include <iostream>
#include <ios>
#include <string>
#include <type_traits>
#include <memory>
struct value
{
~value() = default;
std::unique_ptr<std::string> s;
};
int main()
{
std::cout << std::boolalpha;
std::cout << std::is_move_constructible<value>::value << '\n';
std::cout << std::is_move_assignable<value>::value << '\n';
using str_ptr = std::unique_ptr<std::string>;
std::cout << std::is_move_constructible<str_ptr>::value << '\n';
std::cout << std::is_move_assignable<str_ptr>::value << '\n';
return 0;
}
Выход (скомпилирован с g++ v4.7.2, http://ideone.com/CkW1tG):
false false true true
Как я и ожидал, value
не перемещается конструктивно и не переносится назначаемым, потому что:
~value() = default;
- объявленный пользователем деструктор, который предотвращает неявное генерирование элементов перемещения в соответствии с разделом 12.8 (см. ниже).
Если деструктор удален, то value
перемещается конструктивно и перемещается назначаемым, как я ожидаю (http://ideone.com/VcR2eq).
Однако, когда определение value
изменяется на (http://ideone.com/M8LHEA):
struct value
{
~value() = default;
std::string s; // std::unique_ptr<> removed
};
вывод:
true true true true
value
неожиданно перемещается конструктивно и переносится назначаемым.
Я недопонимаю или это ошибка компилятора?
Справочная информация. Я предоставил ответ на этот вопрос и был проинформирован о том, что Tree<>
был подвижным, но я не уверен, и я пытаюсь точно определить, или нет.
Раздел 8.4.2 Явно-дефолтные функции стандарта С++ 11 (черновик n3337):
Явно-дефолтные функции и неявно объявленные функции совместно именуемые дефолтными функциями, а реализация должна предоставить им неявные определения (12.1 12.4, 12.8), что может означать определяя их как удаленные. Специальная функция-член предоставляется пользователю, если она объявлена пользователем и явно не дефолт или не удаляется по его первой декларации. Предоставляемая пользователем функция с явно дефолтом (т.е. Явно дефолт после его первого объявления) определяется в точке, где она явно дефолт; если такая функция неявно определяется как удаленная, программа плохо сформирована. [Примечание. Объявление функции по умолчанию после ее первая декларация может обеспечить эффективное выполнение и краткое определение, в то время как позволяя стабильный двоичный интерфейс к развивающейся базе кода.-end note]
Раздел 12.8 Копирование и перемещение объектов класса (пункт 9):
If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if - X does not have a user-declared copy constructor, - X does not have a user-declared copy assignment operator, - X does not have a user-declared move assignment operator, - X does not have a user-declared destructor, and - the move constructor would not be implicitly defined as deleted.