Menu
Coddy logo textTech

Szablony wariadyczne

Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 67 z 104.

A co, jeśli potrzebujesz funkcji, która przyjmuje dowolną liczbę argumentów dowolnych typów? Tradycyjne szablony wymagają określenia dokładnej liczby potrzebnych parametrów typów. Szablony wariadyczne rozwiązują ten problem, umożliwiając szablonom przyjmowanie dowolnej liczby argumentów szablonu.

Składnia używa ... (wielokropka), aby utworzyć pakiet parametrów:

template <typename... Args>
void printAll(Args... args) {
    // Args to pakiet parametrów szablonu
    // args to pakiet parametrów funkcji
}

Aby przetwarzać argumenty, zazwyczaj używa się rekurencji z przypadkiem bazowym. Pakiet parametrów rozwija się po jednym argumencie, aż nie pozostanie żaden:

// Przypadek bazowy: nie pozostały żadne argumenty
void print() {
    std::cout << std::endl;
}

// Przypadek rekurencyjny: przetwórz pierwszy argument, wywołaj funkcję rekurencyjnie dla pozostałych
template <typename T, typename... Rest>
void print(T first, Rest... rest) {
    std::cout << first << " ";
    print(rest...);  // Rozwiń pozostałe argumenty
}

print(1, 3.14, "hello", 'x');  // Wynik: 1 3.14 hello x

Możesz również używać wyrażeń składanych (C++17) do prostszych operacji bez jawnej rekurencji:

template <typename... Args>
auto sum(Args... args) {
    return (args + ...);  // Wyrażenie fold: dodaje wszystkie argumenty
}

std::cout << sum(1, 2, 3, 4) << std::endl;  // Wynik: 10

Szablony wariadyczne stanowią podstawę wielu funkcji biblioteki standardowej, takich jak std::make_unique, std::tuple i std::function. Umożliwiają tworzenie bezpiecznych pod względem typów funkcji, które działają z dowolną kombinacją typów i liczby argumentów.

challenge icon

Wyzwanie

Łatwy

Zbudujmy elastyczny system logowania, który wykorzystuje szablony wariadyczne do obsługi komunikatów z dowolną liczbą argumentów. Utworzysz narzędzia, które mogą łączyć wartości, zliczać argumenty i drukować sformatowany wynik — wszystko z użyciem pakietów parametrów.

Rozmieścisz swój kod w dwóch plikach:

  • Variadic.h: Zdefiniuj tutaj swoje funkcje szablonów wariadycznych.

    Utwórz funkcję printAll, która drukuje wszystkie argumenty oddzielone spacjami, a na końcu znak nowej linii. Zastosuj podejście rekurencyjne z przypadkiem bazowym, który drukuje tylko znak nowej linii, oraz przypadkiem rekurencyjnym, który drukuje pierwszy argument, spację, a następnie wywołuje rekurencję dla pozostałych argumentów.

    Utwórz funkcję countArgs, która zwraca liczbę przekazanych do niej argumentów. Użyj sizeof..., aby uzyskać rozmiar pakietu parametrów.

    Utwórz funkcję sum, która dodaje wszystkie argumenty liczbowe i zwraca wynik. Użyj wyrażenia zwijającego z operatorem +.

    Utwórz funkcję product, która mnoży wszystkie argumenty liczbowe i zwraca wynik. Użyj wyrażenia zwijającego z operatorem *.

  • main.cpp: Odczytaj cztery dane wejściowe (każdą w osobnym wierszu):
    1. Liczba całkowita
    2. Liczba typu double
    3. Ciąg znaków
    4. Znak

    Zademonstruj działanie swoich szablonów wariadycznych, wykonując następujące czynności:

    1. Wywołaj printAll ze wszystkimi czterema danymi wejściowymi i wydrukuj wynik
    2. Wydrukuj liczbę argumentów, wywołując countArgs z liczbą całkowitą, liczbą typu double i znakiem: Argument count: <count>
    3. Oblicz sumę liczby całkowitej, liczby typu double oraz wartości 10 i 5, a następnie wydrukuj: Sum: <result>
    4. Oblicz iloczyn liczby całkowitej oraz wartości 2 i 3, a następnie wydrukuj: Product: <result>
    5. Wywołaj printAll tylko z ciągiem znaków (jeden argument)
    6. Wywołaj printAll bez argumentów (powinien wydrukować tylko znak nowej linii)

Na przykład dla danych wejściowych 5, 2.5, Hello i X:

5 2.5 Hello X 
Argument count: 3
Sum: 22.5
Product: 30
Hello 

Zwróć uwagę, jak printAll obsługuje dowolną liczbę argumentów różnych typów — od czterech argumentów aż do zera. Funkcje sum i product używają wyrażeń zwijających, aby elegancko łączyć wszystkie wartości bez jawnej rekurencji. Funkcja countArgs pokazuje, jak sizeof... pozwala uzyskać rozmiar pakietu w czasie kompilacji.

Spróbuj swoich sił

#include <iostream>
#include <string>
#include "Variadic.h"

using namespace std;

int main() {
    // Wczytaj dane wejściowe
    int intVal;
    double doubleVal;
    string strVal;
    char charVal;
    
    cin >> intVal;
    cin >> doubleVal;
    cin >> strVal;
    cin >> charVal;
    
    // TODO: Wywołaj printAll ze wszystkimi czterema danymi wejściowymi
    
    // TODO: Wypisz liczbę argumentów, używając countArgs z intVal, doubleVal i charVal
    // Format: "Argument count: <count>"
    
    // TODO: Oblicz i wypisz sumę intVal, doubleVal, 10 i 5
    // Format: "Sum: <result>"
    
    // TODO: Oblicz i wypisz iloczyn intVal, 2 i 3
    // Format: "Product: <result>"
    
    // TODO: Wywołaj printAll tylko z ciągiem znaków
    
    // TODO: Wywołaj printAll bez argumentów
    
    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C++ online