Istruzioni di Selezione (if e switch)
Le Selection Statements esprimono flussi di controllo condizionali. Fondamentalmente abbiamo le varianti di if e switch.
La Dichiarazione di Inizializzazione (if)
Section titled “La Dichiarazione di Inizializzazione (if)”Una peculiarità eccellente del C++ moderno è poter agganciare lo scope di un oggetto unicamente alla durata della dichiarazione if. Se l’oggetto ci serve solo per processarlo nella condizione di if, è inutile sporcare l’ambiente globale dichiarandolo “prima”.
Sintassi: if (inizializzazione; espressione_condizionale) { ... }
Diventa portentoso se mescolato col fresco Structured Binding:
Lo stesso esatto schema switch (inizializzazione; espressione) si applica volendo agli statement switch.
Il Potentissimo “constexpr if” (C++17)
Section titled “Il Potentissimo “constexpr if” (C++17)”Nel capitolo 6 sui Template abbiamo lottato contro le magagne del Compile-Time Polymorphism. La keyword constexpr if è una vera rivoluzione salvifica.
Se usiamo un if tradizionale in un Template e passiamo un “tipo sbagliato”, l’intero corpo della funzione viene ispezionato dal compilatore generandoci un cratere di errori illeggibili.
Inserendo constexpr if, la condizione viene valutata rigorosamente a tempo di compilazione.
Il miracolo vero è questo: i blocchi di codice che finiscono in un branch falso (condizione non soddisfatta) vengono DISINTEGRATI E IGNORATI TOTALMENTE DAL COMPILATORE. Non genereranno errori di compilazione, è come se non li avessi scritti!
Il constexpr if ha parzialmente sgonfiato la tremenda verbosità dell’antica Template Metaprogramming, permettendo agli sviluppatori di librerie di fornire pattern customizzati e scartabili basati sugli attributi del Type iniettato.
Lo Statement Switch e il Fallthrough
Section titled “Lo Statement Switch e il Fallthrough”Lo statement switch valuta un’espressione e salta al blocco case corrispondente. A differenza di molti altri linguaggi moderni, in C/C++ i case non sono isolati: se non inserisci esplicitamente un’istruzione break alla fine di un blocco case, l’esecuzione “cadrà” (fall-through) eseguendo anche i blocchi dei case successivi, indipendentemente dal fatto che la loro condizione sia vera o falsa!
Questo comportamento, retaggio del C, è spesso causa di bug atroci. Se il fall-through è intenzionale (es. più case devono eseguire la stessa logica), nel C++ moderno dovresti usare l’attributo [[fallthrough]]; per silenziare i giusti allarmi del compilatore.
switch (stato_connessione) { case Stato::DISCONNESSO: printf("Tentativo di riconnessione...\\n"); // Ho scordato il break! Bug fatale! // L'esecuzione cadrà nel case CONNESSO! case Stato::CONNESSO: printf("Inizio trasmissione dati...\\n"); break;}Esattamente come con l’if, dal C++17 è possibile dichiarare variabili locali all’interno del costrutto switch, limitandone la vita vitale al solo blocco dello switch stesso:
switch (Result res = fetch_data(); res.code) { case 200: /* usa res */ break; case 404: /* usa res */ break;}// 'res' non esiste più