Namespaces
Variants

switch statement

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
switch
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Transfère le contrôle à l'une des plusieurs instructions, en fonction de la valeur d'une condition.

Table des matières

Syntaxe

attr  (optionnel) switch ( init-statement  (optionnel) condition ) statement
attr - (depuis C++11) n'importe quel nombre d' attributs
init-statement - (depuis C++17) l'un des éléments suivants :
(depuis C++23)

Notez que toute init-statement doit se terminer par un point-virgule. C'est pourquoi elle est souvent décrite informellement comme une expression ou une déclaration suivie d'un point-virgule.

condition - une condition
statement - une instruction (généralement une instruction composée)

Condition

Une condition peut être soit une expression soit une déclaration simple .

(depuis C++26)
  • S'il peut être résolu syntaxiquement comme une expression, il est traité comme une expression. Sinon, il est traité comme une déclaration qui n'est pas une déclaration de décomposition structurée (depuis C++26) .

Lorsque le contrôle atteint la condition, celle-ci produira une valeur, qui est utilisée pour déterminer vers quelle étiquette le contrôle se dirigera.

Expression

Si condition est une expression, la valeur qu'elle produit est la valeur de l'expression.

Déclaration

Si condition est une déclaration simple, la valeur qu'elle produit est la valeur de la variable de décision (voir ci-dessous).

Déclaration non structurée de liaison

La déclaration comporte les restrictions suivantes :

  • Conforme syntaxiquement à la forme suivante :
  • type-specifier-seq declarator = assignment-expression
(jusqu'en C++11)
  • attribute-specifier-seq (optionnel) decl-specifier-seq declarator brace-or-equal-initializer
(depuis C++11)

La variable de décision de la déclaration est la variable déclarée.

Déclaration de liaison structurée

La déclaration présente les restrictions suivantes :

  • L' expression dans son initialiseur ne peut pas être de type tableau.
  • La séquence de spécificateurs de déclaration ne peut contenir que des spécificateurs de type et constexpr .

La variable de décision de la déclaration est la variable inventée e introduite par la déclaration .

(depuis C++26)

Type

condition ne peut produire que les types suivants :

  • types intégraux
  • types énumérés
  • types de classe

Si la valeur produite est d'un type classe, elle est implicitement convertie contextuellement en un type intégral ou énumération.

Si le type (éventuellement converti) est soumis aux promotions intégrales , la valeur obtenue est convertie vers le type promu.

Étiquettes

Toute instruction au sein de l'instruction switch peut être étiquetée avec une ou plusieurs des étiquettes suivantes :

attr  (optionnel) case constant-expression : (1)
attr  (optionnel) default: (2)
attr - (depuis C++11) n'importe quel nombre d' attributs
constant-expression - une expression constante convertie du type ajusté de la condition switch


Une case ou une étiquette default est associée à l'instruction switch la plus imbriquée qui l'encadre.

Si l'une des conditions suivantes est satisfaite, le programme est mal formé :

  • Une instruction switch est associée à plusieurs étiquettes case dont les expressions-constantes ont la même valeur après conversions.
  • Une instruction switch est associée à plusieurs étiquettes default .

Transfert du flux de contrôle

Lorsque la condition d'une instruction switch produit une valeur (éventuellement convertie) :

  • Si l'une des constantes d'étiquette case associées a la même valeur, le contrôle est transféré à l'instruction étiquetée par l'étiquette case correspondante.
  • Sinon, s'il existe une étiquette default associée, le contrôle est transféré à l'instruction étiquetée par l'étiquette default .
  • Sinon, aucune des instructions dans l'instruction switch ne sera exécutée.

case et default labels en eux-mêmes n'altèrent pas le flux de contrôle. Pour sortir d'une instruction switch depuis le milieu, voir les break statements .

Les compilateurs peuvent émettre des avertissements en cas de fallthrough (atteindre l'étiquette case ou default suivante sans break ) sauf si l'attribut [[ fallthrough ]] apparaît immédiatement avant l'étiquette case pour indiquer que le fallthrough est intentionnel (depuis C++17) .

switch (1)
{
    case 1:
        std::cout << '1'; // affiche "1",
    case 2:
        std::cout << '2'; // puis affiche "2"
}
switch (1)
{
    case 1:
        std::cout << '1'; // affiche "1"
        break;            // et quitte le switch
    case 2:
        std::cout << '2';
        break;
}

switch instructions avec initialiseur

Si une instruction-init est utilisée, l'instruction switch est équivalente à

{
instruction-init
switch ( condition ) instruction

}

Sauf que les noms déclarés par l' instruction-init (si l' instruction-init est une déclaration) et les noms déclarés par la condition (si la condition est une déclaration) sont dans la même portée, qui est également la portée de l' instruction .

(depuis C++17)

Notes

Parce que le transfert de contrôle n'est pas autorisé à entrer dans la portée d'une variable, si une instruction de déclaration est rencontrée à l'intérieur de la statement , elle doit être délimitée dans son propre bloc composé :

switch (1)
{
    case 1:
        int x = 0; // initialisation
        std::cout << x << '\n';
        break;
    default:
        // erreur de compilation : saut vers default :
        // entrerait dans la portée de 'x' sans l'initialiser
        std::cout << "default\n";
        break;
}
switch (1)
{
    case 1:
        {
            int x = 0;
            std::cout << x << '\n';
            break;
        } // la portée de 'x' se termine ici
    default:
        std::cout << "default\n"; // aucune erreur
        break;
}

Mots-clés

switch , case , default

Exemple

Le code suivant montre plusieurs cas d'utilisation de l'instruction switch :

#include <iostream>
int main()
{
    const int i = 2;
    switch (i)
    {
        case 1:
            std::cout << '1';
        case 2:              // l'exécution commence à cette étiquette case
            std::cout << '2';
        case 3:
            std::cout << '3';
            [[fallthrough]]; // attribut C++17 pour supprimer l'avertissement sur le fallthrough
        case 5:
            std::cout << "45";
            break;           // l'exécution des instructions suivantes est terminée
        case 6:
            std::cout << '6';
    }
    std::cout << '\n';
    switch (i)
    {
        case 4:
            std::cout << 'a';
        default:
            std::cout << 'd'; // il n'y a pas d'expressions constantes applicables
                              // donc default est exécuté
    }
    std::cout << '\n';
    switch (i)
    {
        case 4:
            std::cout << 'a'; // rien n'est exécuté
    }
    // lorsque des énumérations sont utilisées dans une instruction switch, de nombreux compilateurs
    // émettent des avertissements si l'un des énumérateurs n'est pas géré
    enum color { RED, GREEN, BLUE };
    switch (RED)
    {
        case RED:
            std::cout << "red\n";
            break;
        case GREEN:
            std::cout << "green\n";
            break;
        case BLUE:
            std::cout << "blue\n";
            break;
    }
    // la syntaxe d'instruction d'initialisation de C++17 peut être utile lorsqu'il n'y a
    // pas de conversion implicite vers un type intégral ou d'énumération
    struct Device
    {
        enum State { SLEEP, READY, BAD };
        auto state() const { return m_state; }
        /* ... */
    private:
        State m_state{};
    };
    switch (auto dev = Device{}; dev.state())
    {
        case Device::SLEEP:
            /* ... */
            break;
        case Device::READY:
            /* ... */
            break;
        case Device::BAD:
            /* ... */
            break;
    }
    // exemples pathologiques
    // l'instruction ne doit pas nécessairement être une instruction composée
    switch (0)
        std::cout << "this does nothing\n";
    // les étiquettes ne nécessitent pas non plus une instruction composée
    switch (int n = 1)
        case 0:
        case 1:
            std::cout << n << '\n';
}

Sortie :

2345
d
red
1

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement tel que publié Comportement correct
CWG 1767 C++98 condition s de types non soumis à
la promotion entière ne pouvaient pas être promues
ne pas promouvoir
condition s de ces types
CWG 2629 C++98 condition pouvait être une déclaration d'une variable à virgule flottante interdit

Voir aussi

Documentation C pour switch

Liens externes

1. Déroulage de boucle utilisant le Dispositif de Duff
2. Le dispositif de Duff peut être utilisé pour implémenter des coroutines en C/C++