variable values usar type dato como booleano bool c++ boolean safe-bool-idiom

values - dato booleano en c++



C++ Bool wrapper seguro (4)

Estoy intentando diseñar una estructura de envoltura bool aplicando el lenguaje bool seguro .
La implementación clásica para resolver esto es bastante trivial: el esqueleto podría ser algo como esto:

struct Bool final { Bool() = default; Bool(bool value) : _value{value} {} explicit operator bool() const { return _value; } private: bool _value{false}; };

La parte que estoy tratando de mejorar es cómo se construye Bool .
Por ejemplo, quiero evitar el estrechamiento implícito por diseño:

Bool b1(45); // yields warnings, but it compiles Bool b2{3}; // not ok by standard

Intenté hacerme daño usando plantillas, pero sin éxito.

¿Cómo podría hacerlo funcionar?


Estoy intentando diseñar una estructura de envoltura bool aplicando el lenguaje bool seguro.

No lo hagas

El lenguaje bool seguro solo es relevante en C ++ 03 y versiones anteriores, donde si expresas que tu tipo es "sincero" al hacer algo como:

struct A { operator bool() const; };

Te encontrarías con todo tipo de problemas como:

A{} + 4; // ok?! A{} < 0; // ok?! A{} == B{}; // ok if B also has operator bool??!

Así que el lenguaje seguro de bool fue una solución a este problema de conversión implícita accidental, utilizando punteros de función (¡por supuesto, punteros de función!).

En C ++ 11, tenemos una solución mucho mejor :

struct A { explicit operator bool() const; };

Que hace exactamente lo que queremos. De hecho, fue diseñado literalmente para resolver este problema. Y mientras que el lenguaje bool seguro es un andamio bastante complicado, explicit operator bool es super sencillo de usar y simplemente hace lo correcto. No necesita una envoltura para ella; en realidad, es más difícil usar su envoltura que escribir directamente el explicit operator bool .

Además, su envoltura impone al usuario (a) no derivabilidad porque hizo que Bool final y (b) un miembro bool extra, que debe mantener sincronizado, por lo que introduce problemas en lugar de resolverlos. Considere cuánto más trabajo sería para usted implementar:

template <class T> struct my_unique_ptr : Bool { ... };

vs

template <class T> struct my_unique_ptr { T* ptr; explicit operator bool() const { return ptr; } };


Agregue, y elimine explícitamente un constructor de plantillas:

template <typename T> Bool(T) = delete;

Coincide con cualquier otra cosa que no sea bool real mejor que otros constructores, y así evitará la conversión implícita.


Puedes lograr esto eliminando explícitamente todos los otros constructores.

struct Bool final { template<class T> Bool(T) = delete; Bool(bool value); };


Si solo necesitas:
Una variable que solo es "verdadera" o "falsa" y no se puede convertir implícitamente a int / char / pointer, entonces vería usando una clase enum:

enum class Bool { False, True, };