Sobes.tech
Senior

Qu'est-ce que SFINAE (Substitution Failure Is Not An Error) en C++?

sobes.tech IA

Réponse de l'IA

SFINAE (L’échec de substitution n’est pas une erreur) est une règle en C++ qui stipule que si le compilateur tente de substituer les arguments d’un modèle dans la signature d’une fonction ou d’une classe, et que cette substitution conduit à un code incorrect (par exemple, tenter d’utiliser un membre qui n’existe pas pour ce type), cela n’est pas considéré comme une erreur de compilation immédiate. Au lieu de cela, le compilateur ignore simplement cette instance du modèle lors de la résolution des surcharges ou des spécialisations.

Cette règle est utilisée pour la métaprogrammation à la compilation, permettant de créer des modèles dont le comportement dépend des propriétés des arguments du modèle.

Exemples d’utilisation de SFINAE :

  • Choix entre des fonctions surchargées ou des spécialisations de modèles de classes en fonction de la présence de certains membres ou opérations supportées.
  • Mise en œuvre de concepts (avant C++20, où les concepts explicites sont apparus) pour restreindre les types de modèles.
  • Création de traits de type.

Exemple d’utilisation de SFINAE avec std::enable_if :

#include <iostream>
#include <type_traits> // Pour std::enable_if

// Modèle de fonction qui ne se compile que pour les types entiers
template <typename T>
typename std::enable_if<std::is_integral<T>::value, void>::type
print_if_integral(T value) {
    std::cout << "Type entier : " << value << std::endl;
}

// Modèle de fonction qui ne se compile que pour les types à virgule flottante
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, void>::type
print_if_floating_point(T value) {
    std::cout << "Type à virgule flottante : " << value << std::endl;
}

int main() {
    print_if_integral(5);       // Appelle la première fonction
    print_if_floating_point(3.14); // Appelle la deuxième fonction
    // print_if_integral("bonjour"); // Erreur de compilation - substitution échouée, fonctions ignorées

    return 0;
}

Dans cet exemple, std::enable_if est utilisé comme type de retour. Si la condition std::is_integral<T>::value est vraie, alors std::enable_if fournit le type void. Si la condition est fausse, std::enable_if ne fournit pas le membre type, ce qui conduit à un échec de substitution dans la signature de la fonction, et le compilateur ignore cette spécialisation de fonction.