if constexpr în C++

Un if evaluat la compilare: ramura falsă este eliminată complet, deci poate conține cod care nu s-ar compila pentru tipul curent.

Sintaxă
if constexpr (conditie_la_compilare) {
    ...
} else {
    ...
}

Ce face if constexpr

if constexpr se folosește mai ales în șabloane (template). Condiția trebuie cunoscută la compilare, de exemplu o întrebare despre tip: std::is_integral_v<T>. Compilatorul păstrează doar ramura adevărată; cealaltă nu este nici măcar verificată pentru tipul respectiv.

Cu un if obișnuit, ambele ramuri trebuie să fie cod valid pentru fiecare tip. De exemplu, nu poți apela .size() pe un int, nici măcar într-o ramură care nu se execută. Cu if constexpr, poți.

Înlocuiește multe tehnici vechi și greu de citit (SFINAE, std::enable_if, specializări separate).

Exemple

Exemplul 1: Comportament diferit după tip

Pentru int ramura cu .size() este eliminată; pentru std::string este eliminată ramura cu numere. Cu un if obișnuit, codul nu s-ar compila.

#include <print>
#include <string>
#include <type_traits>

template <typename T>
void descrie(const T& valoare) {
    if constexpr (std::is_integral_v<T>) {
        std::println("{} este un număr întreg, dublul lui: {}", valoare, valoare * 2);
    } else if constexpr (std::is_same_v<T, std::string>) {
        std::println("\"{}\" este un text cu {} caractere", valoare, valoare.size());
    } else {
        std::println("{} este alt tip", valoare);
    }
}

int main() {
    descrie(21);
    descrie(std::string("Cluj"));
    descrie(3.5);
}

Rezultat

21 este un număr întreg, dublul lui: 42
"Cluj" este un text cu 4 caractere
3.5 este alt tip

Exemplul 2: Recursivitate pe argumente variabile

if constexpr oprește recursivitatea când nu mai sunt argumente; fără el ar trebui o funcție separată pentru cazul de oprire.

#include <print>

template <typename Primul, typename... Restul>
void afiseaza_tot(const Primul& primul, const Restul&... restul) {
    std::print("{}", primul);
    if constexpr (sizeof...(restul) > 0) {
        std::print(", ");
        afiseaza_tot(restul...);
    } else {
        std::println("");
    }
}

int main() {
    afiseaza_tot("Ana", 10, 9.5, 'A');
}

Rezultat

Ana, 10, 9.5, A

Greșeli frecvente

  • Folosești în condiție o valoare cunoscută doar la rulare (if constexpr (n > 5) cu n parametru obișnuit). Nu se compilează; condiția trebuie să fie constantă.
  • Folosești if constexpr în afara unui șablon și te aștepți ca ramura falsă să nu fie verificată. În cod obișnuit (non-șablon), ambele ramuri sunt verificate de compilator.

Comenzi înrudite

  • if, else: Execută un bloc de cod doar dacă o condiție este adevărată; else oferă varianta pentru cazul contrar.
  • template: Scrie o funcție sau o clasă o singură dată, pentru orice tip; compilatorul generează varianta potrivită pentru fiecare tip folosit.
  • constexpr: Cere ca o valoare să fie calculată la compilare; o funcție constexpr poate rula atât la compilare, cât și la rulare.
  • concept: Dă un nume unui set de cerințe pentru tipuri, folosit ca să restrângi ce tipuri acceptă un șablon.
  • std::is_same: Verifică la compilare dacă două tipuri sunt exact același tip.
  • std::enable_if: Activează o funcție-șablon doar pentru tipurile care îndeplinesc o condiție (tehnica SFINAE).