W niektórych przypadkach możliwe jest napisanie funkcji, które nie zachowują się zgodnie z oczekiwaniami, gdy zostaną wywołane z wartościami określonych typów.
Rozważ następujący przykład:
#include <iostream>
void printInt(int x)
{
std::cout << x << '\n';
}
int main()
{
printInt(5); // okay: prints 5
printInt('a'); // prints 97 -- does this make sense?
printInt(true); // print 1 -- does this make sense?
return 0;
}Ten przykład wyświetla:
5 97 1
Chociaż printInt(5) jest całkowicie w porządku, pozostałe dwa wywołania printInt() są bardziej wątpliwe. Za pomocą printInt('a') kompilator ustali, że może awansować 'a' do wartości int 97 w celu dopasowania wywołania funkcji do definicji funkcji. I będzie promować true do wartości int 1. I zrobi to bez narzekania.
Załóżmy, że według nas nie ma sensu wywoływać printInt() z wartością typu char lub bool. Co możemy zrobić?
Usunięcie funkcji za pomocą specyfikatora = delete
W przypadku, gdy mamy funkcję, której wyraźnie nie chcemy, aby była wywoływalna, możemy zdefiniować tę funkcję jako usuniętą za pomocą specyfikatora = usuń . Jeśli kompilator dopasuje wywołanie funkcji do usuniętej funkcji, kompilacja zostanie zatrzymana z powodu błędu kompilacji.
Oto zaktualizowana wersja powyższego wykorzystująca tę składnię:
#include <iostream>
void printInt(int x)
{
std::cout << x << '\n';
}
void printInt(char) = delete; // calls to this function will halt compilation
void printInt(bool) = delete; // calls to this function will halt compilation
int main()
{
printInt(97); // okay
printInt('a'); // compile error: function deleted
printInt(true); // compile error: function deleted
printInt(5.0); // compile error: ambiguous match
return 0;
}Przyjrzyjmy się niektórym z nich. Po pierwsze, printInt('a') jest bezpośrednim dopasowaniem do printInt(char), które zostało usunięte. W ten sposób kompilator generuje błąd kompilacji. printInt(true) jest bezpośrednim dopasowaniem do printInt(bool), które jest usuwane, a zatem również generuje błąd kompilacji.
printInt(5.0) jest interesującym przypadkiem, z być może nieoczekiwanymi wynikami. Najpierw kompilator sprawdza, czy istnieje dokładne dopasowanie printInt(double) . Tak nie jest. Następnie kompilator próbuje znaleźć najlepsze dopasowanie. Chociaż printInt(int) jest jedyną nieusuniętą funkcją, usunięte funkcje są nadal uważane za kandydatów w rozpoznawaniu przeciążenia funkcji. Ponieważ żadna z tych funkcji nie jest jednoznacznie najlepiej dopasowana, kompilator zgłosi błąd kompilacji dopasowania niejednoznacznego.
Kluczowa informacja
= delete oznacza „Zabraniam tego”, a nie „to nie istnieje”.
Usunięta funkcja uczestniczy we wszystkich etapach rozwiązywania przeciążenia funkcji (nie tylko w fazie dokładnego dopasowania). Jeśli zostanie wybrana usunięta funkcja, pojawi się błąd kompilacji.
Dla zaawansowanych czytelników
Inne typy funkcji można usunąć w podobny sposób.
Usuwanie funkcji składowych omawiamy w lekcji 14.14 -- Wprowadzenie do konstruktora kopiującego i usuwanie specjalizacji szablonów funkcji na lekcji 11.7 -- Szablon funkcji instancja.
Usuwanie wszystkich niepasujących przeciążenia Zaawansowane
Usunięcie kilku pojedynczych przeciążeń funkcji działa dobrze, ale może być zbyt szczegółowe. Może się zdarzyć, że będziemy chcieli, aby określona funkcja była wywoływana tylko z argumentami, których typy dokładnie odpowiadają parametrom funkcji. Możemy to zrobić za pomocą szablonu funkcji (przedstawionego w nadchodzącej lekcji 11.6 -- Szablony funkcji) w następujący sposób:
#include <iostream>
// This function will take precedence for arguments of type int
void printInt(int x)
{
std::cout << x << '\n';
}
// This function template will take precedence for arguments of other types
// Since this function template is deleted, calls to it will halt compilation
template <typename T>
void printInt(T x) = delete;
int main()
{
printInt(97); // okay
printInt('a'); // compile error
printInt(true); // compile error
return 0;
}
