• [^] # Re: Typage structurel

    Posté par . En réponse au journal C++ Hell/Heaven et les concepts. Évalué à 3.

    Pour compléter les autres réponses, il y a un mécanicisme un peu plus complexe mais plus puissant (et qui est celui utilisé dans le journal). Il se base sur une règle du C++ abrégée en SFINAE (Substitution Failure Is Not An Error). L'idée est que si, lors de la substitution d'un type dans un template, on obtient une déclaration que n'a pas de sens, le compilateur ignore la fonction au lieu d'émettre une erreur. Ça ne marche que dans la déclaration (paramètres du template, type de retour, ou types des paramètres), pas dans le corps de la fonction.

    #include <iostream>
    template<typename T>
    typename T::A f(T) {
     std::cout << "J'ai un type imbriqué A" << std::endl;
     return {};
    }
    template<typename T>
    typename T::B f(T) {
     std::cout << "J'ai un type imbriqué B" << std::endl;
     return {};
    }
    struct Type1 {
     using A = int;
    };
    struct Type2 {
     using B = int;
    };
    int main() {
     f(Type1{});
     f(Type2{});
     return 0;
    }

    Ce qui donne :

    J'ai un type imbriqué A
    J'ai un type imbriqué B

    Pas d'erreurs puisqu'à chaque fois exactement une des fonctions est gardée. Si un type avait à la fois une type imbriqué A et B, les deux fonctions seraient valide et le compilateur générerait une erreur comme il ne saurait pas choisir. Si un type n'a aucune des deux propriétés, les deux fonctions sont ignorées et le compilateur génère une erreur disant que f n'existe pas (mais s'il est sympa, il t'explique pourquoi il a ignoré les deux possibilités avec un message à rallonge).

    Ça permet d'avoir des fonctions surchargées qui sélectionnent la bonne alternative en fonction des propriétés d'un type paramètre du template. Évidemment, si la condition que tu veux avoir n'est pas un type que tu utilises en retour ou en paramètre, ça devient plus compliqué mais beaucoup de choses sont possibles. Les concepts de C++20 simplifient largement tout ça.

    Pour aider à l'utilisation avancée du SFINAE pré-C++20, il y avait quelques aides comme enable_if et une TS proposait d'ajouter des détecteurs (mais c'est sûrement devenu obsolète avec les concepts).