Template variadici
Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 67 di 104.
E se ti servisse una funzione che accetta un numero qualsiasi di argomenti di qualsiasi tipo? I template tradizionali richiedono di specificare esattamente quanti parametri di tipo ti servono. I template variadici risolvono questo problema consentendo ai template di accettare un numero arbitrario di argomenti di template.
La sintassi usa ... (puntini di sospensione) per creare un pacchetto di parametri:
template <typename... Args>
void printAll(Args... args) {
// Args è un pacchetto di parametri del template
// args è un pacchetto di parametri della funzione
}Per elaborare gli argomenti, in genere si usa la ricorsione con un caso base. Il pacchetto di parametri si espande un argomento alla volta finché non ne rimane nessuno:
// Caso base: nessun argomento rimasto
void print() {
std::cout << std::endl;
}
// Caso ricorsivo: elabora il primo argomento, poi richiama la funzione con i restanti
template <typename T, typename... Rest>
void print(T first, Rest... rest) {
std::cout << first << " ";
print(rest...); // Espandi gli argomenti rimanenti
}
print(1, 3.14, "hello", 'x'); // Output: 1 3.14 hello xPuoi anche usare le espressioni fold (C++17) per operazioni più semplici senza ricorsione esplicita:
template <typename... Args>
auto sum(Args... args) {
return (args + ...); // Fold expression: adds all arguments
}
std::cout << sum(1, 2, 3, 4) << std::endl; // Output: 10I template variadici alimentano molte funzionalità della libreria standard, come std::make_unique, std::tuple e std::function. Consentono di creare funzioni type-safe che funzionano con qualsiasi combinazione di tipi e numero di argomenti.
Sfida
FacileCostruiamo un sistema di registrazione flessibile che usa template variadici per gestire messaggi con un numero qualsiasi di argomenti. Creerai utilità in grado di concatenare valori, contare gli argomenti e stampare un output formattato: tutto usando pacchetti di parametri.
Organizzerai il codice in due file:
Variadic.h: definisci qui le tue funzioni template variadiche.Crea una funzione
printAllche stampa tutti i suoi argomenti separati da spazi, seguiti da una nuova riga. Usa l'approccio ricorsivo con un caso base che stampa solo una nuova riga e un caso ricorsivo che stampa il primo argomento, uno spazio, quindi richiama ricorsivamente la funzione con gli argomenti rimanenti.Crea una funzione
countArgsche restituisce il numero di argomenti passati. Usasizeof...per ottenere la dimensione del pacchetto di parametri.Crea una funzione
sumche somma tutti gli argomenti numerici e restituisce il risultato. Usa un'espressione fold con l'operatore+.Crea una funzione
productche moltiplica tutti gli argomenti numerici e restituisce il risultato. Usa un'espressione fold con l'operatore*.main.cpp: leggi quattro input (ciascuno su una riga separata):- Un intero
- Un double
- Una stringa
- Un carattere
Mostra come funzionano i tuoi template variadici:
- Chiama
printAllcon tutti e quattro gli input e stampa il risultato - Stampa il conteggio degli argomenti quando chiami
countArgscon l'intero, il double e il carattere:Argument count: <count> - Calcola la somma dell'intero, del double e dei valori 10 e 5, quindi stampa:
Sum: <result> - Calcola il prodotto dell'intero e dei valori 2 e 3, quindi stampa:
Product: <result> - Chiama
printAllsolo con la stringa (un singolo argomento) - Chiama
printAllsenza argomenti (dovrebbe stampare solo una nuova riga)
Per esempio, con gli input 5, 2.5, Hello e X:
5 2.5 Hello X
Argument count: 3
Sum: 22.5
Product: 30
Hello
Nota come printAll gestisce un numero qualsiasi di argomenti di tipi diversi, da quattro a zero. Le funzioni sum e product usano espressioni fold per combinare elegantemente tutti i valori senza ricorrere a una ricorsione esplicita. La funzione countArgs mostra come sizeof... fornisca la dimensione del pacchetto in fase di compilazione.
Provalo tu
#include <iostream>
#include <string>
#include "Variadic.h"
using namespace std;
int main() {
// Read inputs
int intVal;
double doubleVal;
string strVal;
char charVal;
cin >> intVal;
cin >> doubleVal;
cin >> strVal;
cin >> charVal;
// TODO: Call printAll with all four inputs
// TODO: Print argument count using countArgs with intVal, doubleVal, and charVal
// Format: "Argument count: <count>"
// TODO: Calculate and print sum of intVal, doubleVal, 10, and 5
// Format: "Sum: <result>"
// TODO: Calculate and print product of intVal, 2, and 3
// Format: "Product: <result>"
// TODO: Call printAll with just the string
// TODO: Call printAll with no arguments
return 0;
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniBuild e compilazione in C++File header e file sorgenteNamespace e ambitoIntroduzione alla programmazione orientata agli oggetti in C++Classi e oggetti a confrontoIl puntatore 'this'Metodi (funzioni membro)Attributi (membri dati)Fondamenti di costruttori e distruttoriRiepilogo - Calcolatrice semplice4Proprietà delle classi
Membri di istanza e staticiGetter e setterFunzioni membro constParola chiave mutableMetodi e variabili staticiFunzioni e classi friendRiepilogo - Gestore di conti bancari7Ereditarietà
Ereditarietà di baseLivelli di accesso nell’ereditarietàOrdine di chiamata di costruttori e distruttoriRidefinizione dei metodiFunzioni virtuali e VTableEreditarietà multiplaEreditarietà virtualeRiepilogo - Gerarchia dei dipendenti2Gestione della memoria
Memoria Stack vs HeapPuntatori e riferimentiMemoria dinamica (new/delete)Puntatori intelligenti in C++RAII in C++Riepilogo - Gestore di array dinamico5Incapsulamento
Specificatori di accesso in C++Specificatori di accesso in dettaglioOccultamento delle informazioniStruct vs classClassi annidate e interneRiepilogo - Sistema di registrazione degli studenti8Polimorfismo
Polimorfismo a compile time e a runtimeOverload delle funzioniFunzioni virtuali: ripassoFunzioni virtuali pureClassi astratteProgettazione delle interfacce in C++Dynamic casting e RTTIRipasso: calcolatrice di forme11Concetti avanzati di OOP
Composizione vs ereditarietàMixin tramite CRTPIdiom PimplType ErasureEnum class e tipizzazione forteGestione delle eccezioni in OOPGerarchie personalizzate di eccezioni14Pattern di progettazione - Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeRAII come pattern3Costruttori e distruttori
Costruttore predefinitoCostruttore con parametriCostruttore di copiaCostruttore di spostamentoListe di inizializzazione dei costruttoriCostruttori delegantiApprofondimento sui distruttoriRegola del Tre / Cinque / ZeroRipasso - classe String6Sovraccarico degli operatori
Introduzione al sovraccarico degli operatoriSovraccarico degli operatori aritmeticiSovraccarico degli operatori di confrontoOperatori di flussoSovraccarico dell'operatore di assegnazioneSovraccarico degli operatori [] e ()Operatori di conversione di tipoRipasso - Classe Matrix9Template
Template di funzioneTemplate di classeSpecializzazione dei templateTemplate variadiciBasi di SFINAE e dei trait di tipoRiepilogo - Contenitore genericoEsercitati da solo: Compilatore C++ online