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'); // drukuje 97 -- czy to ma sens?
printInt(true); // drukuj 1 -- czy to ma sens?
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; // wywołania tej funkcji zatrzymają kompilację
void printInt(bool) = delete; // wywołania tej funkcji zatrzymają kompilację
int main()
{
printInt(97); // okay
printInt('a'); // błąd kompilacji: funkcja usunięta
printInt(true); // błąd kompilacji: funkcja usunięta
printInt(5.0); // błąd kompilacji: niejednoznaczne dopasowanie
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>
// Ta funkcja będzie miała pierwszeństwo w przypadku argumentów typu int
void printInt(int x)
{
std::cout << x << '\n';
}
// Ten szablon funkcji będzie miał pierwszeństwo w przypadku argumentów innych typów
// Ponieważ ten szablon funkcji zostanie usunięty, wywołania go zatrzymają kompilację
template <typename T>
void printInt(T x) = delete;
int main()
{
printInt(97); // okay
printInt('a'); // compile error
printInt(true); // compile error
return 0;
}
