2017-06-10 3 views
5

En lecture de code en ligne des bibliothèques de production que je trouve quelque chose comme çaComment éviter de violer ODR avec des traits les classes

Traits.hpp

template <typename Type> 
class Traits { 
    template <typename T, 
       detail::EnableIfIsInstantiation<T, Type>* = nullptr> 
    static void foo(T& object) { 
     object.foo(); 
    } 
}; 

SpecialTraits.hpp

template <> 
class Traits<Special> { 
    static void foo(Special& object) { 
     object.foo(); 
    } 
    static void foo(Special&& object) { 
     object.special_foo(); 
    } 
}; 

Cela provoquera une violation ODR si une bibliothèque instancie un type qui utilise Traits pour Something dans une unité de traduction sans inclure SpecialTraits.hpp, puis instancie un type qui utilise les traits spécialisés dans une autre unité de traduction. Cela entraînerait une violation ODR lorsque ces deux unités de traduction sont liées ensemble.

Quelle est la méthode suggérée pour éviter ce problème? Dois-je recourir à toutes les spécialisations du fichier original Traits.hpp? Et si je ne suis pas autorisé à modifier le fichier avec la définition de Special?

Remarque S'il vous plaît ignorer le fait que foo() aurait pu être spécialisés par lui-même Special dans le cas &&. Je ne pouvais pas penser à un meilleur exemple ..

+1

Mettez la spécialisation dans le même en-tête que la définition de 'Special'. –

+0

@PeteBecker Bonne pensée! J'aurais dû inclure cela dans la question. mais que faire si vous n'y avez pas accès? Par exemple, disons qu'il s'agit d'une spécialisation pour un module 'boost' – Curious

+0

Inclure l'en-tête avec la déclaration dans l'en-tête avec la spécialisation, et n'inclure que le dernier. –

Répondre

3

Mettez la spécialisation dans "WidgetWrapper.hpp" au lieu de "Widget.hpp" et d'inclure "WidgetWrapper.hpp" partout. Sinon, déposez un rapport de bogue avec Boost et attendez-vous à ce qu'il n'aille nulle part, puisque ce problem exact a été discuté il y a 15 ans sans résolution.