Я хочу знать, когда разрешение на копирование / перемещение применяется (или разрешено применять) явно delete
d копировать / перемещать конструкторы и неdelete
d копировать / перемещать конструкторы. Вот особенности:
Может явно delete
скопировать ctor или переместить ctor? Это попытка создать объект из другого объекта того же типа или временного объекта, который когда-либо позволял добиться успеха, пропуская delete
d скопировать ctor и / или delete
переместить ctor?
Вот что происходит в VC12 (с которым я не уверен, есть ли возможность отключить копирование / перемещение elision):
#include <iostream>
struct Foo {
Foo() { std::cout << "default ctor\n"; }
Foo(Foo const&) = delete;
Foo(Foo&&) = delete;
};
int main() {
// ----Output------
Foo{ Foo() }; // "default ctor"Foo f; // "default ctor"Foo{ std::move(f) }; // error C2280: 'Foo::Foo(Foo &&)' : attempting to reference a deleted function
Foo{ f }; // error C2280: 'Foo::Foo(const Foo &)' : attempting to reference a deleted function
}
Хотя IntelliSense жалуется на Foo{ Foo() };
: Error: function “Foo::Foo(Foo &&)” ... cannot be referenced – it is a deleted function
компилятор там не жалуется, так что строка все еще компилируется.
Почему Foo{ Foo() };
работать, но не Foo{ std::move(f) };
? Если один вызов отменяет ход ctor, то не другой?
Почему Foo{ Foo() };
работать, но не Foo{ f };
? Эта избирательность выглядит произвольно. Этот вид произвольного предпочтения rvalue-ссылки перед const-ссылкой (или наоборот), похоже, не применяется к не-ctor методам; где в вызове, если delete
d перегрузка, которая в противном случае имела бы более высокий приоритет разрешения перегрузки, чемdelete
перегрузка, delete
d один блокируетdelete
d один, что приводит к ошибке компилятора:
struct Bar {
void g(int const&) {}
void g(int&&) = delete;
};
//…
Bar b;
b.g(2); //error C2280: 'void Bar::g(int &&)' : attempting to reference a deleted function
// ^ Would have compiled had function `g(int&&)` been commented out.
Согласно этой логике, delete
d Foo(Foo&&)
не должен блокировать вызов Foo(Foo const&)
когда аргумент не является временным; Foo(Foo&&)
будет иметь более низкий приоритет разрешения перегрузки, чем Foo(Foo const&)
в таком случае.
Я пробовал то же самое Foo
пример в g ++ 4.8 с отключенным разрешением копирования (через флаг -fno-elide-constructors
) и снова с ним включен. Оба испытания g ++ дали:
error: use of deleted function 'Foo::Foo(Foo&&)'
за Foo{ Foo() };
а также
error: use of deleted function 'Foo::Foo(const Foo&)'
за Foo{ f };
Какой компилятор правильный?
У MS VC ++ есть очень старая хорошо известная ошибка. Из стандарта C ++
[Примечание: это двухступенчатое разрешение перегрузки должно быть выполнено
независимо от того, будет ли выполнено копирование. Это определяет
конструктор, который вызывается, если elision не выполняется, и выбранный
Конструктор должен быть доступен, даже если вызов отменен. —Конечная записка]
Других решений пока нет …