Skip to content

Istruzioni di Selezione (if e switch)

Le Selection Statements esprimono flussi di controllo condizionali. Fondamentalmente abbiamo le varianti di if e switch.

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 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ù