Присвоение из rvalue разрешено, когда оператор присваивания явно удален?

Рассмотрим следующий код, который компилируется в Clang, GCC и VS 2015 (онлайн-пример):

#include <utility>

class S 
{
public:
    S(int x) : i(x) { }
    ~S() { }

    S(S&&)  = default;

    S(const S& )            = delete;
    S& operator=(S&&)       = delete;
    S& operator=(const S&)  = delete;

private:
    int i;
};

S GetS() 
{ 
    // This is a contrived example with details elided. Assume 
    // there's a reason in the actual use case for returning via 
    // std::move.
    return std::move( S(999) ); 
}

int main()
{
    S tmp = GetS(); // <-- Assignment allowed even though assignment operator is deleted?

    return 1;
}

Я не понимаю, почему линия

S tmp = GetS(); 

компилируется, выполняя конструктор перемещения вместо оператора присваивания перемещения.

Я знаю, что RVO позволяет исключать построение и присваивание в качестве оптимизации, но я так понимаю, что явное удаление оператора должно привести к сбою компиляции, если этот оператор явно используется в коде.

Есть ли в спецификации C++11 какой-либо пункт, который позволяет компилятору преобразовывать инициализацию присваивания в конструкцию копирования, даже если операторы присваивания для типа были явно удалены?


person Chris Kline    schedule 29.03.2016    source источник
comment
В вашем коде нет ни одного присваивания. И в C++ нет такой вещи, как инициализация присваивания.   -  person AnT    schedule 29.03.2016
comment
Да, ты прав. Хороший улов. Я поправил заголовок.   -  person Chris Kline    schedule 29.03.2016


Ответы (1)


Это потому, что это не задание:

S tmp = GetS(); 

он называется copy-initialization и вызывает конструктор перемещения , который вы явно установили по умолчанию.

По сути, оператор присваивания вызывается только для уже существующего объекта. tmp еще не существует, этот оператор инициализирует его. Таким образом, вы вызываете конструктор.

Обратите внимание, что то, что происходит внутри GetS(), не влияет на правила построения tmp. GetS() в любом случае является rvalue.

person Barry    schedule 29.03.2016
comment
А, это имеет смысл. Я не знал, что инициализация копирования имеет собственный набор правил; Я думал, что это просто общепринятая терминология, используемая для обозначения этой идиомы. Спасибо за объяснение! - person Chris Kline; 29.03.2016