2012-12-29 16 views
11

Powiel możliwe:
Why do C++11-deleted functions participate in overload resolution?C++ 11 "Non-ruchomy" typ

Mam dwa pytania dotyczące następującego kodu C++ 11:

#include <iostream> 

using namespace std; 

struct A { 
    A() { cout << "Default c-tor" << endl; } 
    A(const A&) { cout << "Copy c-tor" << endl; } 
    A(A&&) = delete; 
}; 

A f() 
{ 
A a; 
return a; 
} 

int main() 
{ 
    A b = f(); 
    return 0; 
} 

Otrzymuję następujące błędy kompilacji z gcc i clang

GCC-4.7.2 (g ++ --std = C++ 11 main.cpp)

main.cpp: In function ‘A f()’: 
main.cpp:16:9: error: use of deleted function ‘A::A(A&&)’ 
main.cpp:8:2: error: declared here 
main.cpp: In function ‘int main()’: 
main.cpp:21:10: error: use of deleted function ‘A::A(A&&)’ 
main.cpp:8:2: error: declared here 

szczęk-3,0 (szczęk ++ --std = C++ 11 main.cpp)

main.cpp:19:4: error: call to deleted constructor of 'A' 
     A b = f(); 
     ^ ~~~ 
main.cpp:8:2: note: function has been explicitly marked deleted here 
     A(A&&) = delete; 
     ^
1 error generated. 
  • Czy kompilator nie powinien używać konstruktora kopiowania, jeśli konstruktor ruchu został jawnie usunięty?
  • Czy ktoś wie, że można użyć dowolnego typu "nie ruchomego"?

Z góry dziękuję.

+1

http://stackoverflow.com/questions/14085620/why-do-c11-deleted-functions-participate-in-overload-resolution – paulm

+0

Zastanawiam się, w jaki sposób zwrócić obiekt lokalny, jeśli 'A (A &&)' jest usunięty. – Nawaz

+0

Właściwie to było moje pierwsze pytanie, czy kompilator nie powinien wybrać konstruktora kopiowania zamiast konstruktora ruchu, gdy konstruktor ruchu zostanie jawnie usunięty? (Rozumiałem, że usunięte funkcje są rozpatrywane w rozdzielczości przeciążenia). – lucasmrod

Odpowiedz

6
A(A&&) = delete; 

Deklarowanie i definiowanie jej jako delete ma jeszcze zadeklarować ją, a nie czyni go całkowicie nieistniejące. Raczej jest to podobny (ale nie identyczny) do deklarowania go puste i prywatne. Tak:

private: 
    A(A&&){} 

w rzeczywistości, to był podstęp czasem wykorzystywane do innych operatorów przed = delete był dostępny. Ponownie, istnieje w sensie wyszukiwania, ale wywoływanie go nie jest nigdy dozwolone, a uprawnienia do wywoływania C++ są (w prawie lub wszystkich przypadkach) wykonywane po wszystkim innym, takim jak rozdzielczość przeciążania, wyszukiwanie nazwy.

Standardowa właściwie powiedzieć (8.4.3)

Usunięta funkcja jest niejawnie inline.

Zauważam, że skasowane funkcje nie powinny brać udziału w wyszukiwaniu nazw.

Również od 8.4.3

program, który odnosi się do usuniętej funkcji lub pośrednio, inne niż to uznania, jest słabo formowane. [Uwaga: Obejmuje to wywołanie funkcji niejawnie lub jawnie i utworzenie wskaźnika do elementu lub wskaźnika do elementu. Obowiązuje nawet dla odniesień w wyrażeniach, które nie są potencjalnie oceniane.

+2

@Nawaz: to jest to samo, co pozostałe dwie odpowiedzi, ponieważ jeśli byłaby naprawdę "nieistniejąca", to nie byłaby rozważana w rozdzielczości przeciążania.Ofc, nie wstawiłbym tego za standard, aby wprowadzić techniczną definicję "istniejącego", która jest sprzeczna z angielskim znaczeniem ;-) Jest rozważana do pewnych celów, ale nie do innych, chociaż nie ma żadnej funkcji, więc różni się od zdefiniowanej prywatnej funkcji powyżej. –

+0

@SteveJessop: Przez egzystencję Johan miał na myśli coś, co nie jest prawdą. Próbował wyjaśnić, co miał na myśli, pokazując odpowiedni kod: on * zdefiniował * to w sekcji prywatnej. – Nawaz

+1

@Nawaz: wzruszając ramionami. Oczywiście nie wiem, co jest w umyśle Johana, ale jestem prawie pewien, że to mniej więcej tyle samo, co pozostałych dwóch odbierających. –

2

To trochę zadania badawczego ale myślę deklarując konstruktor ruch twierdzi, że konstruktor ruch ma być traktowany.Kiedy następnie dostaje delete d, oznacza to, że obiekty mogą być przenoszone tam, gdzie mogłyby zostać przeniesione, gdyby istniał konstruktor ruchu. Jeśli chcesz, aby obiekt, który nie został przeniesiony, ale skopiowany, po prostu zadeklarowałeś konstruktor kopiowania i nie wspomniałbyś o konstruktorze ruchu.

Nie dość znalazł oświadczenie w standardzie, ale, co wyraźnie stwierdza wyżej, ale jest w Note 12.8 [class.copy] pkt 9 backing up część powyższe stwierdzenie:

[ Uwaga: Kiedy konstruktor ruchu nie jest jawnie deklarowany lub jawnie dostarczany, wyrażenia, które w przeciwnym razie wywołałyby konstruktor ruchu, mogą zamiast tego wywołać konstruktor kopiowania. -end note]

2

Po usunięciu konstruktora ruchu nie usuwa go z zestawu funkcji znalezionych przez wyszukiwanie nazwy. Za każdym razem, gdy twój kod normalnie używa konstruktora ruchu, otrzymasz błąd, ponieważ, mimo że został znaleziony, został usunięty.

Masz dwa ruchy w swoim kodzie. Pierwszym z nich jest to, że kiedy możliwe jest kopiowanie, a obiekt, który zostałby skopiowany, jest oznaczany jako l-wartość (a, tutaj), jest traktowany jako ruch. Drugi znajduje się w zadaniu A b = f(), ponieważ f() daje tymczasowy, który nie został jeszcze powiązany z odwołaniem.

Jeśli chcesz, aby znaleziono konstruktora kopiowania zamiast konstruktora usuniętych ruchów, powinieneś po prostu pozbyć się usuniętej definicji.

1

Od C++ projektu Roboczej 2012-11-02

8.4.3 Usunięte definicje [dcl.fct.def.delete]
...
2 Program, który odnosi się do skreślony funkcja pośrednio lub jawnie, inna niż deklaracja, jest źle sformułowana. [Uwaga: Obejmuje to wywołanie funkcji niejawnie lub jawnie i utworzenie dla tej funkcji wskaźnika lub wskaźnika-do-członka . Dotyczy to nawet odniesień w wyrażeniach, które nie są potencjalnie oceniane. Jeżeli funkcja jest przeciążona, odwołuje się do niej tylko wtedy, gdy wybrana funkcja jest wybrana z powodu przeciążenia. - nota końcowa]
...
4 Usunięta funkcja jest niejawnie wbudowana.

Ponieważ odwołuje się usunięty konstruktor ruchu, program jest źle sformułowany.

"Użycie" dla typu nie-ruchomego może uniemożliwić poruszanie się, a zatem uniemożliwić zwrócenie obiektu lokalnego. Sam nie widziałem takiego zastosowania i nie wiem, czy to ma sens, ale YMMV.