2016-10-11 2 views
3

Tout d'abord, j'ai un fichier d'en-tête pour une classe, une déclaration de spécialisation sans définition (échantillons de code à partir d'Internet)Ma spécialisation de modèle diffère de la version de débogage de la version finale, est ce bug gcc?

$ cat foo.h

template<typename T> 
class foo{ 
public: 
    static void init(){ 
     return; 
    } 

}; 

template<> void foo<int>::init(); 

Ensuite, il sommes 2 de mise en œuvre fichiers de spécialisation du modèle

$ cat foo_int.cpp 
#include "foo.h" 
#include<stdio.h> 
template<> 
void foo<int>::init(){ 
    printf("init int foo\n"); 
} 

$ cat foo_float.cpp 
#include "foo.h" 
#include<stdio.h> 
template<> 
void foo<float>::init(){ 
    printf("init float foo\n"); 
} 

Enfin je suis arrivé un fichier principal

$ cat main.cpp 
#include "foo.h" 

int main(){ 
    foo<int>::init(); 
    foo<float>::init(); 
} 

Si je compile sans l'optimisation et l'exécuter, il donne:

g ++ foo_int.cpp foo_float.cpp main.cpp & & a.out
initialisation int foo
flotteur initialisation foo

Si j'ajoute l'optimisation, le résultat est différent:

$ g ++ foo_int.cpp foo_f loat.cpp main.cpp -O2 & & a.out
initialisation int foo

Le résultat est différent. Quelques explications sur internet a dit cela est dû à un mécanisme interne de « symbole faible » dans la mise en œuvre gcc, mais ma question:

  1. Est « faible symbole »/« symbole fort » un concept de gcc/g ++ ou fait partie de la spécification du langage c/C++. Si les résultats du débogage et de la sortie sont différents, devrais-je dire qu'il s'agit d'un bug/problème de gcc/g ++, en ce qui concerne le mécanisme du "symbole faible"? En tant que développeur, je ne m'attendrais pas à ce que ma version de débogage se comporte différemment de la version finale.

J'ai essayé clang, malheureusement même erreur. Est-ce un cas "acceptable" pour C/C++ que debug/release "devrait" se comporter si différemment?

+0

Déclaration de spécialisation de 'void foo :: init()' n'est pas visible dans 'main' ... Votre programme est mal formé. – Jarod42

+0

Faites attention lorsque vous formatez le texte. Seuls les blocs de code conservent les espaces blancs et les sauts de ligne. Lorsque vous avez collé la sortie de la console 'g ++' sous le balisage '>', les sauts de ligne ont tous été écrasés dans une ligne de texte. Pour préserver les sauts de ligne, placez un double espace à la fin de chaque ligne. Ou simplement coller est comme un bloc de code. Les lecteurs n'ont généralement aucun problème à remarquer lequel contient du code et lequel contient du vidage de console :) – quetzalcoatl

+0

"J'ai un fichier d'en-tête pour une classe" - non, vous avez un fichier d'en-tête pour un ** modèle ** . –

Répondre

3

Vous avez violé la une règle de définition — votre programme contient deux définitions de foo<float>::init.

Une définition se produit dans l'unité de compilation foo_float.cpp, et l'autre apparaît dans l'unité de compilation main.cpp.

Violer la règle d'une définition signifie un comportement non défini — dans ce cas, ce qui se passe probablement est:

  • Avec des optimisations au large, le programme génère un appel de fonction réelle, et l'éditeur de liens est arrivé à mettre la version de foo_float.cpp de la fonction dans l'exécutable.
  • Avec des optimisations sur, lors de la compilation main.cpp le compilateur a souligné la fonction — naturellement, il serait en ligne main.cpp version de la fonction.
+0

Dans main.cpp: parce qu'il n'y a pas de déclaration de spécialisation' foo :: init', alors la définition générale est considérée comme la définition de 'foo : : init'? Est-ce la raison? – bolov

3

La définition du langage exige que vous déclariez une spécialisation explicite avant son utilisation:

Si un modèle, un modèle de membre ou un membre d'un modèle de classe est spécialisé explicitement alors que la spécialisation sera déclaré avant la première utilisation de cette spécialisation qui provoquerait une instanciation implicite , dans chaque unité de traduction dans où une telle utilisation se produit; aucun diagnostic n'est requis. [temp.expl.spec]/6.

Il n'y a pas de déclaration de la spécialisation explicite de foo<float>::init() au point où il est appelé à partir main, mais il y a une spécialisation explicite dans foo_float.cpp, de sorte que le comportement du programme est défini.

+0

oui, c'est en fait plus sur le point que la réponse précédente – bolov