8
votes

Différenciation Sfinae entre signée et non signée

J'ai des fonctions pour convertir différents types arithmétiques à un type de point flottant à moitié précision (juste un uint16_t code> au niveau le plus bas) et j'ai des fonctions différentes pour les types de sources de points entier et flottant, en utilisant SFUNE et std :: Enable_if Code>: XXX PRE>

Ceux-ci sont appelés interne à partir d'un constructeur modélisé universel par instanciation explicite: P>

template<typename T>
uint16_t to_half(typename std::enable_if<std::is_integral<T>::value &&
                 std::is_signed<T>::value,T>::type value)
{
    //signed to half conversion
}

template<typename T>
uint16_t to_half(typename std::enable_if<std::is_integral<T>::value &&
                 std::is_unsigned<T>::value,T>::type value)
{
    //unsigned to half conversion
}


5 commentaires

Il n'est pas clair que is_signed / is_unsigned est mutuellement exclusif (bonjour char ?). Essayez de faire la deuxième version dire ! Std :: is_signed :: valeur à la place.


Pouvez-vous essayer d'utiliser std :: is_signed :: valeur pour l'un des membres et ! Std :: is_signed :: valeur pour l'autre? Ceci est juste pour vous assurer qu'il n'y a pas que certains types de paramètres incompatibles pour is_signed et is_unsigned .


@Kerreksb & Dietmar Hah, ça l'a fait! Je ne peux pas croire que c'était aussi facile. Si quelqu'un l'ajoute comme une réponse, je l'accepterai.


@Kerrek Char n'est ni un type d'entier signé ni un type d'entier non signé. Mais IIRC is_signed et is_unsigned prend en charge que: un seul d'entre eux signalera true pour char .


@ Johannesschab-litb: vous avez raison, char est ok. Les énigmes et les pointeurs sont toujours faux, cependant; Je suppose que parce qu'ils ne sont pas des types arithmétiques.


3 Réponses :


3
votes

Si cela ne fonctionne pas, votre compilateur est erroné.

Deux expressions impliquant des paramètres de modèle sont considérés comme équivalents si deux définitions de fonction contenant les expressions satisferaient la règle d'une définition ...

C'est la règle la plus importante à considérer ici (laissé sur les détails de "..."). Vos deux modèles ne satisfont pas l'ODR parce que leurs séquences de jeton diffèrent.

Deux modèles de fonctions sont équivalents si elles sont déclarées dans la même portée, ont le même nom, avoir le même nom, avoir des listes de paramètres de modèle identiques et des types de retour et des listes de paramètres équivalents à l'aide des règles décrites ci-dessus pour comparer des expressions de modèle impliquant des paramètres de modèle.

Donc, vos deux modèles définissent différents modèles et ne vous heurtent pas. Vous pouvez maintenant vérifier si vos modèles sont peut-être «équivalents fonctionnellement». Ils seraient si pour tout ensemble possible d'arguments de modèle, votre expression activer_if donnerait toujours la même valeur. Mais puisque ce n'est pas vrai pour is_unsigned et is_signed , ce n'est pas le cas non plus. Si tel serait le cas, votre code serait mal formé, mais sans nécessiter de diagnostic (ce qui signifie efficacement «comportement non défini»).


7 commentaires

Remplacer is_unsigned avec ! IS_SIGNED (ou inversement) a fonctionné, alors je suppose (bien qu'elles ne soient pas bien versées dans les profondeurs de la spécification de langue, ne pas parler de modèles) qu'il y a un type qui est à la fois signé et américain. Ou peut-il être parce que les versions par défaut de ces modèles évaluent à la fois faux pour les types non arithmétiques? Mais là encore, il y a aussi le is_integral pour désambiguez les choses (pour des types intégrés, SHOUDL sera mutuellement exclusif, ne devrait-il pas?).


@Christian je n'ai aucune idée de ce qu'ils font, mais c'est vraiment un comportement erroné. Essayez !! is_unsigned au lieu de ! Is_signed . Je ne serais pas surpris de le voir "travailler" aussi :)


Hah, ça a fonctionné aussi. Ok maintenant je pense que ça devient vraiment un peu ridicule. Vous avez probablement raison de dire que le compilateur est en faute ici.


"Deux expressions impliquant des paramètres de modèle sont considérées comme équivalentes si deux Les définitions de fonction contenant les expressions satisfont à la règle d'une définition ..." Pourriez-vous expliquer cela plus loin en ajoutant un exemple dans votre message?


Votre réponse n'est que la moitié correcte. Le compilateur a été correct de rejeter le code (voir ma réponse ci-dessous), mais cela a donné la mauvaise raison.


@walter il passe explicitement l'argument


En effet il fait. Étrange. Quel est le point de Sfinae si vous faites cela?



8
votes

Personnellement, j'éviterais Sfinae ici autant que possible puisque vous pouvez accomplir la même chose avec la surcharge: xxx


2 commentaires

+1 belle alternative. Mais comme note latérale, je pense que le dernier argument à la version flottante doit être de std :: true_type , car des flotteurs sont toujours signés (au moins les implémentations habituelles, pour le code de conversion non-IEEE gagné ' t fonctionne de toute façon).


@Christian: Vous êtes totalement correct; Je basais la logique des documents MSDN pour IS_SIGNED , qui se passe mal (surprise, surprise). Fixé.



1
votes

L'idiome le plus courant est d'utiliser Sfinae sur le type de retour plutôt que le type d'argument. sinon , le type de modèle t peut ne pas être déductible . Avec xxx

type t dans l'instruction suivante xxx

est déductible (même de manière triviale), mais pour votre code d'origine ce n'est pas! En effet, lors de l'exécution de cette déclaration avec votre to_half () La mise en œuvre via clang donne xxx

bien sûr, si on fournit explicitement l'argument de modèle (comme vous a fait), ce problème n'apparaît pas. Donc, votre code n'était pas faux (mais le compilateur), mais quel est le point de Sfinae si vous passez le type d'argument de modèle?


2 commentaires

Cela ne devrait-il pas avoir les mêmes problèmes d'ambiguïté que la Sfinae dans le type d'argument? Y a-t-il une règle qui rend ce travail mais la version de l'argument non? Sinon, il ne semble pas tellement adresser la question.


Il y a une très bonne raison pour ne pas utiliser Sfinae sur le type d'argument, voir la réponse modifiée.