programowanieProgramista C++, Starszy programista

Jak działają szablony funkcji i klas z parametrami domyślnymi? Jakie są szczegóły ich użycia i co robić w przypadku sprzeczności między funkcjami szablonowymi a nie-szablonowymi?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Szablony z parametrami domyślnymi to potężny mechanizm programowania ogólnego w C++.

Historia pytania:

Biblioteka STL zaczynała od szablonów. Później pojawiła się możliwość określania wartości domyślnych dla parametrów zarówno funkcji szablonowych, jak i klas, aby uczynić szablony bardziej uniwersalnymi i wspierać rozwijalność kodu.

Problem:

Nieoczywiste konflikty mogą występować, gdy istnieją przeciążenia funkcji zwykłych i szablonowych, a także niejednoznaczności przy specjalizacjach. Parametry domyślne w szablonach mogą zwiększać elastyczność, ale często prowadzą do zagmatwanych błędów kompilacji.

Rozwiązanie:

Lepiej minimalizować liczbę wartości domyślnych w szablonach, zwłaszcza jeśli istnieje nakładanie się z nie-szablonowymi wersjami. Preferencje przy wywołaniu funkcji dają pierwszeństwo dokładnemu dopasowaniu z funkcją zwykłą, a nie szablonową.

Przykład kodu:

template<typename T = int> T multiply(T a, T b = T(2)) { return a * b; } int multiply(int a, int b) { return a + b; }

Wywołanie multiply(5, 4) wybierze funkcję int multiply(int, int), a wywołanie multiply<>(5) wywoła szablon, a b przyjmie wartość 2.

Kluczowe cechy:

  • Wartości domyślne deklarowane są tylko w pierwszym ogłoszeniu/definicji szablonu.
  • Klasyczne funkcje mają pierwszeństwo przed szablonowymi przy zgodności sygnatur.
  • Wartości domyślne dla parametrów szablonów stosowane są tylko w przypadku ich braku w jawnym wywołaniu.

Pytania z podstępem.

Czy można zadeklarować parametry domyślne w kolejnym określeniu funkcji szablonowej?

Nie, wartość domyślna może być podana tylko w jednym miejscu (zwykle w ogłoszeniu), w przeciwnym razie wystąpi błąd kompilacji.

Co się stanie w przypadku niejednoznaczności między szablonem a funkcją nie-szablonową? Jak kompilator wybiera, co wywołać?

Kompilator zawsze będzie preferował funkcję nie-szablonową, jeśli pasuje dokładnie do argumentów. Szablon zostanie wywołany tylko w przypadku braku dokładnego dopasowania.

Czy można podawać wartości domyślne dla nie-typowego parametru szablonu (na przykład dla liczby)?

Tak, na przykład:

template<typename T, int N = 8> class Array { T data[N]; };

Typowe błędy i antywzorce

  • Deklaracja wartości domyślnych jednocześnie w kilku miejscach.
  • Niejasna niejednoznaczność między funkcjami szablonowymi a zwykłymi.
  • Nadmierne użycie parametrów domyślnych, utrudniające czytanie i debugowanie kodu.

Przykład z życia

Negatywny przypadek

Zadeklarowane zostały zarówno funkcja szablonowa, jak i nie-szablonowa z pasującymi parametrami i wartościami domyślnymi. W jednym module wywołanie działa zgodnie z zamysłem, a w innym niespodziewanie wybierana jest nie ta wersja funkcji.

Zalety:

  • Wygodnie wywoływać bez precyzowania typu.

Wady:

  • Nieoczywiste błędy i zagmatwana logika wywołania.

Pozytywny przypadek

Dla nakładających się konfiguracji jasno zadeklarowane różne nazwiska dla funkcji szablonowych i nie-szablonowych, wartości domyślne tylko w jednej z wersji.

Zalety:

  • Wyraźne zachowanie.
  • Brak kolizji w wywołaniach.

Wady:

  • Trochę więcej kodu przy utrzymaniu wersji funkcji.