Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

  1. #1
    Rédacteur/Modérateur

    Template et spécialisation template et optimisation de compilation (-O3) (clang)
    Salut,

    je voulais vous faire part d'une "étrangeté" rencontrée il y a peu.

    Le titre pose le contexte, il s'agit de compiler, sous clang dans mon cas, une fonction template, et surtout une spécialisation template de cette fonction.
    Voyons le cas simplifié, avec une mise en évidence sur un simple cout:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // MyClass.hpp
    class MyClass {
    public:
      template<class T> void Send(const T& _k);
    };
    template<class T> void MyClass::Send(const T& _k) { std::cout<<"base template method"<<std::endl; }

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    // MyClass.cpp
    template<>
    void MyClass::Send(const Item& _k) { std::cout<<"specialization for Item"<<std::cout; }

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    // AnotherFile.cpp
    ...
    Item k;
    GetMyclass()->Send(k);
    ...


    Et c'est là que les ennuis commencent.

    Sans optimisation, en debug classique, la spécialisation est correctement appelée.
    Mais en Release/Master, optimisé, non ! Le linker ne tient pas compte de la spécialisation présente dans une autre unité de compilation.

    Pour résoudre ça : forward declaration de spécialisation template.
    Derrière ce nom barbare, une simple ligne template<> void MyClass::Send(const Item& _k); à placer dans le header.
    Donc le fichier devient:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // MyClass.hpp
    class MyClass {
    public:
      template<class T> void Send(const T& _k);
    };
    template<class T> void MyClass::Send(const T& _k) { std::cout<<"base template method"<<std::endl; }
    template<> void MyClass::Send(const Item& _k);

    La spécialisation est à placer en dehors de la définition de la classe. Sinon vous serez victime d'un message d'erreur
    error : explicit specialization of 'Send' in class scope
    Notez que vous pouvez aussi implémenter la spécialisation dans le header, ce qui corrige également le problème. Mais c'est pas toujours possible. Ni très propre amha.

    C'était mes 2 centimes du jour, qui pourraient vous aussi vous sauver plusieurs heures/jours !
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  2. #2
    Membre éclairé
    A vrai dire Bousk, bien que je sois loin d'être hyper à l'aise avec les templates, je ne comprends pas pourquoi ça marche en debug.

    Comment le compilateur peut-il savoir quelle spécialisation appeler si elle n'est pas au moins déclarée dans la même unité de compilation ?

  3. #3
    Rédacteur/Modérateur

    Après coup c'est facile de déclarer ça et on a eu la même réaction : "mais WTF que ça marchait en debug en fait ?! c'est totalement logique que ça marche pas! Comment en debug il pouvait trouver la spécialisation présente dans une autre unité de compilation ?"
    En tous cas c'est clair : en debug, sans optim, ça passe, en O3, ça casse. Je n'ai pas testé d'autres modes, mais c'est pas assuré que ça marche pas aussi avec O1 et O2 en optim.
    Bref, je voulais juste partager ce "trick" qui nous est apparus.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.