2015-03-04 1 views
8

Je veux faire un équivalent à boost::swap et dans mon environnement, les en-têtes standard peuvent, ou ne peuvent pas être inclus. Selon la licence du projet et d'autres choses.
Je voudrais faire des parties du code protégées par des détecteurs de garde:Existe-t-il un moyen de détecter de façon portative qu'un en-tête standard est inclus en utilisant des macros?

Considérons une unité de compilation.
projet spécifique, le potentiel ci-écrit comprend:

#include <algorithm> // (or <utility> for C++11 projects) 

plus tard dans le code du projet inclus de mon en-tête de service d'échange:

namespace MyCompany 
{ 
    template<class T1, class T2> 
    void swap(T1& left, T2& right) 
    { 
    #ifdef _ALGORITHM_ // you get the idea. 
     std::swap(left, right); 
    #else 
     // fallback impl 
    #endif 
    } 
} 

J'ai simplifié parce que nous ne parlons pas de détails de l'affaire ADL ici, mais il sera inclus.
ici pour la référence de ce dont je parle, mais cela n'a aucune importance à cette question:
http://www.boost.org/doc/libs/1_57_0/boost/core/swap.hpp

Donc, cette question est sur le point, comment puis-je détecter l'inclusion d'en-tête standard? le gardien _ALGORITHM_ est présent dans l'en-tête visual studio fourni, mais je n'ai lu nulle part sur http://www.cplusplus.com/reference/algorithm/ qu'il devrait avoir n'importe quelle macro que je peux vérifier.

(note finale: cette question est un peu XY peu biaisée Ce que je veux vraiment est de détecter la présence de la fonction std::swap, pas l'en-tête..)

+0

Donc, vous voulez l'inverse? Utiliser un échange spécialisé comme solution de repli? –

+0

disons, comme une convention, les clients de notre codebase utiliseront MyCompany :: swap comme fonction d'échange par défaut, les mêmes utilisateurs de stimuler la façon dont ont largement adopté boost :: échange. Cependant, l'implémentation de ce swap spécial, pourrait utiliser std :: swap en interne dans le cas où les types T1 et T2 étant permutés ont une spécialisation de std :: swap. Mais si les en-têtes standard ne sont pas inclus à ce stade (parce que mon utilitaire ne les inclura pas en raison du respect des règles de licence plus strictes), je veux le détecter et ne jamais appeler std :: swap. –

+3

Je respecte votre intention mais cela conduit à des bogues difficiles à traquer à long terme; le code du client peut silencieusement changer de comportement en fonction ou non '' #include , et vous devrez traiter les demandes de support client –

Répondre

4

Une option que vous avez à faire votre surcharger un "pire match" que les alternatives. Alors, que si elles ne sont pas déjà sera votre version sélectionné:

#if 0 
#include <algorithm> 
using std::swap; 
#endif 

template <typename T> 
struct ForceLessSpecialized { 
    typedef T TYPE; 
}; 

template <typename T> 
void swap (T &, typename ForceLessSpecialized<T>::TYPE &) { 
} 

void bar() { 
    int i; 
    swap (i, i); 
} 

Qu'est-ce qui se passe:

Quand il y a deux spécialisations de modèle de fonction candidat, le compilateur effectue « commande partielle de modèles de fonction "('03 14.5.5.2). Cela vérifie si les paramètres du modèle de fonction d'un modèle peuvent être utilisés pour spécialiser l'autre.

Pour chaque modèle, nous allons utiliser les paramètres fictifs T1 et T2 et nous créons des listes d'arguments fictifs en utilisant ces types:

// std::swap argument list 
(T1 & , T1 &) 

// our swap argument list 
(T2 &, typename ForceLessSpecialized<T2>::TYPE &) 

Spécialisée notre échange en utilisant les arguments factices de std::swap donne:

Deduction from First parameter: T == T1 
Deduction from Second parameter: Non Deduced Context 

La déduction T est T1 et la déduction a réussi.

Spécialisée std::swap en utilisant les arguments factices pour notre échange donne:

Deduction from First parameter: T == T2 
Deduction from Second parameter: T == ForceLessSpecialized<T2>::TYPE 

Les types de T sont déduites pas les mêmes, et si cela est considéré comme un échec de la déduction.

Par conséquent, les arguments synthétisés de std::swap peuvent être utilisés pour spécialiser notre modèle, mais les arguments synthétisés de notre modèle ne peuvent pas être utilisés pour se spécialiser std::swap. std::swap est considéré comme étant plus spécialisé et remporte ainsi l'ordonnance partielle.

+0

putain, c'est du bon travail. certainement une bonne lecture à prendre de la norme. 14.5.5.2 fait référence aux classes, le paragraphe actuel est 14.5.6.2, mais il y a un lien vers celui-ci. merci :) c'est marrant parce qu'hier j'ai lu l'interprétation de Herb Sutter sur "pourquoi ne pas spécialiser les modèles de fonction". http://www.gotw.ca/publications/mill17.htm bonne lecture ainsi –

+0

@ v.oddou: Comme vous le soulignez paragraphe dans les normes les plus récentes est 14.5.6.2, j'utilisais la norme '03 qui a comme 14.5.5.2. –