2017-06-19 2 views
1

J'essaye de calculer GCD, au moment de la compilation en utilisant la spécialisation partielle du template. Le code suivant fonctionne correctement avec clang3.8 mais pas avec gcc7.1. Avec GCC, il s'agit d'une instanciation de modèle récursif sans réaliser de cas de terminaison.Problème de spécialisation de template partiel C++ avec gcc

template <int N, int M>                                    
struct GCD{                                       
    static const int value = (N>M)? GCD<N%M, M>::value : GCD<N, M%N>::value;                       
};                                         

template <int M>                                      
struct GCD<0, M>{                                      
    static const int value = M;                                  
};                                         

template <int M>                                      
struct GCD<M, 0>{                                      
    static const int value = M;                                  
};                                         


int main()                                       
{                                          
    static_assert(GCD<12,15>::value == 3, "Error");                               
} 

Qui se comporte normalement?

+0

Peut-être faire seulement une déclaration avant de la structure 'GCD' à deux arguments, avec la définition ci-dessous les spécialisations. Parce qu'au moment de la première définition, le compilateur ne connaît pas vraiment les deux spécialisations. Quel compilateur est correct, je ne le sais pas. –

+0

Notez qu'en C++ 17, il y aura une fonction ['gcd'] (http://en.cppreference.com/w/cpp/numeric/gcd) dans l'en-tête' '. – InternetAussie

+0

Et vos maths ne fonctionnent pas ici. –

Répondre

1

Si vous voulez résoudre le problème, je propose l'amélioration suivante

template <int N, int M, bool = (M != 0) && (N != 0) && (N > M)> 
struct GCD; 

template <int N, int M> 
struct GCD<N, M, true> 
{ static constexpr int value { GCD<N%M, M>::value }; }; 

template <int N, int M> 
struct GCD<N, M, false> 
{ static constexpr int value { GCD<N, M%N>::value } ; }; 

template <int M> 
struct GCD<0, M, false> 
{ static constexpr int value { M }; }; 

template <int M> 
struct GCD<M, 0, false> 
{ static constexpr int value { M }; }; 

Si vous voulez savoir si est droit g ++ ou ++ clang, bien ... Je ne sais pas quoi, exactement, un compilateur peut ou doit faire dans ces circonstances alors ... je ne sais pas.

Justement, je ne sais pas, quand N > M et une rencontre du compilateur,

 static const int value = (N>M)? GCD<N%M, M>::value : GCD<N, M%N>::value;                                                

si le compilateur doit (ou peut) mettre en œuvre que GCD<N%M, M> ou si doit (ou peut) mettre en œuvre GCD<N, M%N> aussi. Quoi qu'il en soit, si je ne me trompe pas, clang ++ ne met en œuvre que GCD<N%M, M> où g ++ implémente les deux.

Mon amélioration est adaptée pour éviter ce problème.

+0

Vous avez raison, gcc implémente les deux. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81134 –