J'essaie de concevoir une structure bool wrapper en appliquant le idiome booléen sûr.
L'implémentation classique pour résoudre ce problème est assez banale: le squelette pourrait ressembler à ceci:
struct Bool final
{
Bool() = default;
Bool(bool value)
: _value{value}
{}
explicit operator bool() const {
return _value;
}
private:
bool _value{false};
};
La partie que j'essaye d'améliorer est de savoir comment Bool
est construit.
Par exemple, je veux éviter un rétrécissement implicite par conception:
Bool b1(45); // yields warnings, but it compiles
Bool b2{3}; // not ok by standard
J'ai essayé de me blesser en utilisant des modèles, mais sans succès.
Comment pourrais-je le faire fonctionner?
Vous pouvez y parvenir en supprimant explicitement tous les autres constructeurs.
struct Bool final
{
template<class T>
Bool(T) = delete;
Bool(bool value);
};
Ajoutez et supprimez explicitement un constructeur de modèle:
template <typename T>
Bool(T) = delete;
Il correspond à tout autre chose que bool
réel mieux que les autres constructeurs, et empêchera ainsi la conversion implicite.
Si vous avez juste besoin de:
Une variable qui n'est que "vraie" ou "fausse" et qui ne peut pas être implicitement convertie en int/char/pointeur alors je regarderais en utilisant une classe enum:
enum class Bool {
False,
True,
};
J'essaie de concevoir une structure d'encapsuleur booléen appliquant l'idiome booléen sûr.
Non.
L'idiome Safe Bool n'est pertinent qu'en C++ 03 et versions antérieures - où si vous exprimez que votre type est "véridique" en faisant quelque chose comme:
struct A {
operator bool() const;
};
vous rencontriez toutes sortes de problèmes comme:
A{} + 4; // ok?!
A{} < 0; // ok?!
A{} == B{}; // ok if B also has operator bool??!
Ainsi, l'idiome Safe Bool était une solution à ce problème de conversion implicite accidentelle, en utilisant des pointeurs de fonction (bien sûr, des pointeurs de fonction!).
En C++ 11, nous avons une solution bien meilleure :
struct A {
explicit operator bool() const;
};
qui fait exactement ce que nous voulons. En fait, c'était littéralement conç pour résoudre ce problème. Et tandis que l'idiome Safe Bool est un échafaudage assez compliqué, explicit operator bool
est super simple à utiliser et fait juste la bonne chose. Vous n'avez pas besoin d'un wrapper pour cela - il est en fait plus difficile d'utiliser votre wrapper que d'écrire le explicit operator bool
directement.
De plus, votre wrapper impose à l'utilisateur (a) la non-dérivabilité parce que vous avez créé Bool
final et (b) un membre supplémentaire bool
, que vous devez garder synchronisé, donc il introduit plutôt que résout les problèmes. Considérez combien de travail il vous faudrait mettre en œuvre:
template <class T>
struct my_unique_ptr : Bool { ... };
contre
template <class T>
struct my_unique_ptr {
T* ptr;
explicit operator bool() const { return ptr; }
};