2017-05-03 4 views
0

Je doute que gcc 4.8.3 inline des fonctions de template incorrectes ... Ce problème ne se produit pas en mode debug, mais seulement en mode optimisé. Cependant, cela se produit dans une base de code compliquée, je ne suis pas capable de reproduire le problème dans un cas de test simple.gcc inline la fonction de template générique avec une définition spécialisée

Mon code est comme ce qui suit

#include "stdio.h" 

class A { 
public: 

    template<typename T> int WriteNative(const T) { 
     printf("here?\n") 
     return 0; 
    } 

    template<typename D> 
     void doit() { 
     if (WriteNative<double>(1)) { 
      printf("A\n"); 
     } else { 
      printf("B\n"); 
     } 
    } 

}; 

// in my real code, this definition is in a different cpp file 
template<> int A::WriteNative<double>(const double) { 
    return 1; 
} 

int main() { 
    A a; 
    a.doit<float>(); 
} 

En version debug, il imprime A, tandis que dans la construction optimisée, il imprime ici? \ NB

Je suppose que tout Inliner utilise le modèle générique définition de la fonction, mais pas celle spécialisée. Mais attribut ((noinline)) n'aide pas.

Est-ce que quelqu'un si mon code a un comportement défini de C++? et comment résoudre ce problème?

+0

Ma solution de contournement que j'ai trouvée est en insérant les définitions spécialisées: http://stackoverflow.com/questions/4445654/multiple-definition-of-template-specialization-when-using-different-objects. –

Répondre

2

Vous ne le dites pas explicitement, mais j'imagine que dans votre code actuel, vous ne parveniez pas à déclarer la spécialisation dans le fichier .h de A. Ainsi, lorsque A.h était inclus dans une unité de compilation séparée, le compilateur ignorait la spécialisation de WriteNative(). Ajout d'une déclaration de la spécialisation devrait résoudre le problème sans avoir à inclure la définition dans le même fichier (par exemple, ne pas avoir à inline il):

class A { 
    public: 
    template<typename T> int WriteNative(const T) { 
     printf("here?\n") 
     return 0; 
    } 

    template<typename D> 
     void doit() { 
     if (WriteNative<double>(1)) { 
      printf("A\n"); 
     } else { 
      printf("B\n"); 
     } 
    } 
}; 
template<> int A::WriteNative(const double); 

Vous pouvez reproduire votre problème en utilisant trois fichiers A.h, A.cpp, et main.cpp, où A.cpp contient la définition de la spécialisation, de sorte que lorsque main.cpp comprend A.h, il ne connaît pas la spécialisation quand inline se produit lors de l'optimisation, et lorsqu'il est compilé avec -O0, pas inline se produit, alors WriteNative() se reliera contre la définition A.cpp .

Édition: Voir ce answer qui cite la spécification pour expliquer pourquoi ce comportement est correct.

14.7.3 [temp.expl.spec]:

6/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 doit être déclarée avant la 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. Si le programme ne fournit pas de définition pour une spécialisation explicite et que la spécialisation est utilisée d'une manière qui provoquerait une instanciation implicite ou si le membre est une fonction virtuelle membre , le programme est mal formé, aucun diagnostic requis. Une instanciation implicite n'est jamais générée pour une spécialisation explicite déclarée mais non définie.

+0

Est-ce que déclarer la spécialisation dans le fichier d'en-tête demandé par C++? –

+1

Ce n'est pas le cas. Mais d'autres unités de compilation ne le verront pas, évidemment.C'est une question de ce qui se passe pendant la compilation et de ce qui se passe pendant le couplage. –

+0

@ n.caillou Si cela n'est pas nécessaire, l'optimisation me semble trop agressive. Je pense qu'une optimisation de compilateur ne devrait pas changer comment le code fonctionne à moins que mon code original sans la déclaration soit indéfini. –