Какая точная семантика удаленной функции в С++ 11?
struct A
{
A();
A(const A&);
A& operator =(const A&);
A(A&&) = delete;
A& operator =(A&&) = delete;
};
struct B
{
B();
B(const B&);
B& operator =(const B&);
};
int main()
{
A a;
a = A(); // error C2280
B b;
b = B(); // OK
}
Мой компилятор - это VС++ 2013 RC.
ошибка C2280: 'A & A:: operator = (A & &)': попытка ссылаться на удаленная функция
Мне просто интересно, почему компилятор не пытается A& operator =(const A&);
, когда A& operator =(A&&)
удален?
Является ли это поведение определенным стандартом С++?
Ответы
Ответ 1
a = A(); // error C2280
Выражение справа является временным, что означает, что он будет искать operator=(A&&)
и видит, что он удален. Отсюда и ошибка. Дальнейшего поиска больше нет.
=delete
означает, что не означает "не используйте меня, а используйте следующий лучший". Это скорее означает: "Не используйте меня, когда вам нужно, вместо того, чтобы быть одинок в дикой природе".
Вот еще один пример. Если я хочу, чтобы экземпляры моего класса X
были созданы только с long
, и другого типа (даже если он преобразуется в long!), Я бы объявил class X
как:
struct X
{
X(long arg); //ONLY long - NO int, short, char, double, etc!
template<typename T>
X(T) = delete;
};
X a(1); //error - 1 is int
X b(1L); //ok - 1L is long
Это означает, что разрешение перегрузки выполняется до того, как компилятор увидит =delete
part — и, следовательно, приводит к ошибке, поскольку выбранная перегрузка найдена удаленной.
Надеюсь, что это поможет.
Ответ 2
Когда вы =delete
выполняете функцию, вы фактически удаляете ее определение.
8.4.3 Удаленные определения [dcl.fct.def.delete]
1 Определение функции вида:
атрибут-спецификатор-seqopt decl-specifier-seqopt declarator = delete;
называется удаленным определением. Функция с удаленным определением также называется удаленной функцией.
Но тем самым вы также объявляете эту функцию. Цитирование из стандарта [1]:
4 Удаленная функция неявно встроена. [Примечание. Правило с одним определением (3.2) применяется к удаленным определениям. -end note] Удаленное определение функции должно быть первым объявлением функции [...]
И поэтому, делая a = A()
, компилятор фактически разрешает A::operator=(A&&)
, потому что он был объявлен (не A::operator(const A&)
, потому что A&&
является "более привязкой" к r-значениям). Однако, когда его определение будет удалено, линия плохо сформирована.
2 Программа, которая ссылается на удаленную функцию неявно или явно, кроме объявления, плохо сформирована.
[1] Тон подчеркнутого предложения здесь действительно необходим. В стандарте указывается, что объявление функции =delete
d должно сначала отображаться перед другими объявлениями. Тем не менее, он поддерживает тот факт, что удаление функции также объявляет функцию.