La limitation de la gamme de types de valeur en C++
Supposons que j'ai un LimitedValue classe qui détient une valeur, et est paramétrée sur int types 'min' et 'max'. Vous souhaitez utiliser comme un contenant pour les valeurs qui ne peuvent être que dans une certaine plage. Vous pouvez l'utiliser tel:
LimitedValue< float, 0, 360 > someAngle( 45.0 );
someTrigFunction( someAngle );
de sorte que " someTrigFunction sait qu'il est garanti pour être fourni à une entrée valide (Le constructeur lève une exception si le paramètre n'est pas valide).
La copie de la construction et de l'affectation sont limitées exactement égale types. J'aimerais être capable de faire:
LimitedValue< float, 0, 90 > smallAngle( 45.0 );
LimitedValue< float, 0, 360 > anyAngle( smallAngle );
et le fonctionnement vérifié à la compilation, donc l'exemple suivant donne une erreur:
LimitedValue< float, -90, 0 > negativeAngle( -45.0 );
LimitedValue< float, 0, 360 > postiveAngle( negativeAngle ); //ERROR!
Est-ce possible? Est-il un moyen pratique de faire cela, ou des exemples qui approche ce?
Vous devez vous connecter pour publier un commentaire.
Vous pouvez le faire à l'aide de modèles -- essayez quelque chose comme ceci:
OK, c'est le C++11 avec pas de Boost dépendances.
Tout garanti par le système de type est vérifiée au moment de la compilation, et rien d'autre, déclenche une exception.
J'ai ajouté
unsafe_bounded_cast
pour les conversions que peut jeter, etsafe_bounded_cast
pour les conversions explicites qui sont statiquement correcte (ce qui est superflu, puisque le constructeur de copie qu'il gère, mais à condition de symétrie et d'expressivité).Exemple D'Utilisation
Exception De Soutien
C'est un peu passe-partout-y, mais ne donne assez lisible à l'exception des messages comme ci-dessus (le min/max/valeur sont exposées ainsi, si vous choisissez d'attraper la dérivée type d'exception et peut faire quelque chose d'utile avec elle).
Valeur Classe
Cast Soutien
T runtime_value
au lieu deint runtime_value
?constexpr
serait un meilleur choix queenum
puisque c'est censé être unC++11
solution.Le Boost Limitée de la Valeur de la bibliothèque(1) permet d'ajouter des contraintes de types de données.
Mais vous avez qu'à lire l'avis "Pourquoi C++de virgule flottante types ne doit pas être utilisé avec délimitée objets?" lorsque vous souhaitez l'utiliser avec flotteur types (comme illustré dans l'exemple).
(1) la poussée de La Contrainte de la Valeur de la bibliothèque n'est pas un officiel de la bibliothèque Boost encore.
La délimité::integer bibliothèque fait ce que vous voulez (pour les types d'entiers seulement). http://doublewise.net/c++/borné/
(Dans l'intérêt de la divulgation complète, je suis l'auteur de cette bibliothèque)
Il diffère des autres bibliothèques qui tentent de fournir des "safe entiers" de manière significative: elle suit l'entier de limites. Je pense que cela est mieux illustré par l'exemple:
x est un entier de type qui est entre 0 et 7. y est un entier de type entre le 7 et le 7. z est un entier de type entre 7 et 14. Toutes ces informations sont connues au moment de la compilation, c'est pourquoi nous sommes en mesure de static_assert sur elle, même si la valeur de z n'est pas une constante de compilation.
La première affectation,
z = 10_bi
, n'est pas cochée. C'est parce que le compilateur ne peut pas prouver que10
se situe dans la plage dez
.La deuxième cession,
z = x
, vérifie que la valeur dex
est dans la gamme dez
. Si non, il déclenche une exception (le comportement exact dépend du type d'entier que vous utilisez, il existe de nombreuses stratégies de quoi faire).La troisième ligne, le
static_assert
, montre que c'est une erreur de compilation à assigner à partir d'un type qui n'a pas de chevauchement à tous. Le compilateur sait déjà c'est une erreur et ne vous arrête.La bibliothèque n'est pas de convertir implicitement le type sous-jacent, ce qui peut causer beaucoup de situations où vous essayez de l'empêcher quelque chose, mais il se produit en raison de conversions. Il ne permet pas de conversion explicite.
C'est en fait une question complexe et que j'ai réalisées pendant un certain temps...
Maintenant, j'ai mis à disposition du public de la bibliothèque qui vous permettra de limiter floating points et entiers dans votre code, de sorte que vous pouvez faire plus d'assurer qu'ils sont valides en tout temps.
Non seulement que vous pouvez désactiver les limites dans votre version de la version finale et cela signifie que les types assez bien devenir la même chose qu'un
typedef
.Définir votre type:
Et quand vous ne définissez pas la
CONTROLLED_VARS_DEBUG
etCONTROLLED_VARS_LIMITED
drapeaux, vous obtenez à peu près la même chose que ceci:Ces classes sont générées afin qu'ils comprennent tous des opérateurs pour vous de ne pas trop souffrir lors de leur utilisation. Cela signifie que vous pouvez voir votre
angle_t
presque comme unfloat
.Fonctionne comme prévu (et de le jeter si
a + 35 > 360
).http://snapwebsites.org/project/controlled-vars
Je sais que cela a été publié en 2008... mais je ne vois pas de bon lien pour un sommet de la bibliothèque qui offre cette fonctionnalité!?
Pour le moment, ce qui est impossible dans une manière portable en raison du C++ règles sur la façon de méthodes (et, par extension, les constructeurs) sont appelées, même avec les querelles constantes.
Dans le C++0x standard, vous pourriez avoir un const-expr qui permettrait une telle erreur peut être produit si.
(C'est en supposant que vous voulez qu'il lève une erreur si la valeur réelle est illégal. Si les plages ne correspondent pas, vous pouvez atteindre cet objectif)
Une chose à retenir à propos des modèles, c'est que chaque invocation d'un ensemble unique de paramètres de modèle sera le vent de la génération d'un "unique" de la classe pour laquelle les comparaisons et les affectations génère une erreur de compilation. Il peut y avoir un peu de meta-programmation des gourous qui peut savoir comment contourner cela, mais je ne suis pas l'un d'eux. Mon approche serait de mettre en œuvre ces dans une classe avec des temps d'exécution des contrôles et surchargé de comparaison et de l'affectation des opérateurs.
Je voudrais offrir une autre version pour Kasprzol la solution: L'approche proposée utilise toujours les limites de type int. Vous pouvez obtenir un peu plus de souplesse et de sécurité de type avec une mise en œuvre telles que:
Cela va permettre au vérificateur de types d'attraper évident miss affectations telles que:
Cependant, le plus avancé de relations où vous voulez vérifier si la gamme d'un modèle, s'il est inclus dans la gamme d'une autre instance ne peut pas être exprimée dans le C++ mécanisme de template.
Tous les Borné cahier des charges devient un nouveau type. Ainsi, le compilateur peut vérifier les incompatibilités de type. Il ne peut pas vérifier pour les plus avancés des relations qui peuvent exister pour ces types de.
J'ai écrit une classe C++ qui imite la fonctionnalité de Ada
range
.Il est basé sur des modèles similaires sur les solutions fournies ici.
Si quelque chose comme cela, c'est pour être utilisé dans un vrai projet, il sera utilisé d'une façon très fondamentale. Des bogues ou des malentendus peuvent être désastreuses.
Donc, même si c'est une petite bibliothèque, sans beaucoup de code, à mon avis, la fourniture de tests unitaires et claire de la philosophie de design sont très importants.
Hésitez pas à l'essayer et vous me direz si vous trouvez des problèmes.
https://github.com/alkhimey/ConstrainedTypes
http://www.nihamkin.com/2014/09/05/range-constrained-types-in-c++/