L'idée générale
Plutôt que d'énumérer tous les valides des types de fonction, à l'instar de l' exemple de mise en œuvre sur cpprefereence.comcette application répertorie tous les types qui ne sont pas des fonctions, et ensuite seulement résout true
si aucun de ceux-ci est mis en correspondance.
La liste des non-types de fonction se compose de (de bas en haut):
- Les Classes et les syndicats (y compris les types abstract)
- Tout ce qui peut être renvoyée par une fonction (y compris
void
et les types de référence)
- Types de tableau de
Un type qui ne correspond à aucun de ces types de fonction est un type de fonction. Notez que std::is_function
considère explicitement appelable types tels que les lambdas ou des classes avec un appel de fonction de l'opérateur que de ne pas être des fonctions.
is_function_impl_
Nous fournissons une surcharge de l' is_function_impl
fonction pour chacun des cas éventuels de non-types de fonction. Les déclarations de fonction peut être un peu difficile à analyser, donc, nous allons casser vers le bas pour l'exemple des classes et des syndicats cas:
template<typename T, typename = int T::*>
char(&is_function_impl_(priority_tag<3>))[4];
Cette ligne déclare une fonction de modèle is_function_impl_
qui prend un seul argument de type priority_tag<3>
et renvoie une référence à un tableau de 4 char
s. Comme il est de coutume depuis les anciens jours de C, la syntaxe de déclaration devient horriblement compliquée par la présence de types de tableau.
Ce modèle de fonction prend deux arguments de modèle. La première est juste une contrainte T
, mais le second est un pointeur sur un membre de l' T
de type int
. L' int
partie il est question ici n'a pas vraiment d'importance, c'est à dire. ce sera même travail pour T
s qui ne sont pas tous les membres de type int
. Ce qu'il fait est qu'il en résultera une erreur de syntaxe pour T
s qui ne sont pas de classe ou de type d'union. Pour les autres types, d'une tentative d'instancier le modèle de fonction va aboutir à une substitution de l'échec.
Des astuces similaires sont utilisés pour l' priority_tag<2>
et priority_tag<1>
surcharges, qui utilisent leur deuxième modèle arguments pour former des expressions que seuls les compiler pour T
s est valide en fonction des types de retour ou de types de tableau, respectivement. Seulement l' priority_tag<0>
de surcharge n'est pas aussi contraignantes deuxième paramètre de modèle et peut donc être instancié avec tout T
.
Dans l'ensemble, nous déclarer les quatre différentes surcharges pour is_function_impl_
, qui diffèrent par leur argument d'entrée et le type de retour. Chacun d'eux prend une autre priority_tag
type en argument et renvoie une référence à un tableau de char de différentes taille unique.
Tag envoi en is_function
Maintenant, lors de l'instanciation is_function
, il instancie is_function_impl
avec T
. Notez que depuis que nous avons fourni quatre différentes surcharges pour cette fonction, résolution de surcharge a lieu ici. Et depuis toutes ces surcharges sont fonction des modèles, ce qui signifie SFINAE a une chance de coup de pied dans.
Donc, pour les fonctions (et fonctionne uniquement) tous les surcharges échoue à l'exception de la plus générale, avec priority_tag<0>
. Alors pourquoi ne pas l'instanciation toujours résoudre à la surcharge, si c'est le cas le plus général? Parce que des arguments d'entrée de nos fonctions surchargées.
Notez que priority_tag
est construit de telle manière qu' priority_tag<N+1>
public hérite priority_tag<N>
. Maintenant, depuis is_function_impl
est invoquée avec priority_tag<3>
, que la surcharge est un meilleur match que les autres pour la résolution de surcharge, de sorte qu'il sera essayé en premier. Uniquement si cela échoue en raison d'une erreur de substitution à la prochaine meilleure correspondance est essayé, ce qui est l' priority_tag<2>
de surcharge. Nous continuerons dans cette voie jusqu'à ce que nous soit trouver une surcharge qui peut être instancié ou nous arrivons priority_tag<0>
, ce qui n'est pas limité et le sera toujours. Depuis tous les non-types de fonctions sont couverts par la hausse des prio surcharges, ce qui ne peut arriver que pour des types de fonction.
En évaluant le résultat
Nous avons maintenant vérifier la taille du type retourné par l'appel à is_function_impl_
pour évaluer le résultat. Rappelez-vous que chaque surcharge renvoie une référence à un tableau de char de taille différente. Nous pouvons donc utiliser sizeof
pour vérifier la surcharge a été sélectionné et seulement définir le résultat de la true
si nous avons atteint l' priority_tag<0>
de surcharge.
Bugs Connus
Johannes Schaub trouvé un bug dans la mise en œuvre. Un tableau de classe incomplète type seront classés par erreur comme une fonction. C'est parce que l'actuel mécanisme de détection pour les types tableau ne fonctionne pas avec incomplètes types.