2009-05-05 32 views
12

Estoy rediseñando un constructor de clase en C++ y necesito que capture un bool no especificado. He usado valores por defecto para todos los demás parámetros, pero desde mi entender, bool solo se puede inicializar a verdadero o falso. Dado que ambos casos tienen un significado en la clase, ¿cómo debo manejar la verificación de cambio de un valor predeterminado?Valor predeterminado para bool en C++

+7

¿Es importante saber si está utilizando el valor predeterminado "falso" de un "falso" inicializado? – RobS

Respuesta

39

La realidad es que no se puede hacer esto. Un bool tiene valor, ya sea verdadero o falso, y si no lo has inicializado, entonces es aleatoriamente verdadero o falso, posiblemente diferente en cada ejecución del programa o asignación de esa clase.

Si necesita un tipo con más opciones, defina una enumeración.

typedef enum MyBool { 
    TRUE, 
    FALSE, 
    FILENOTFOUND 
} MyBool; 
+16

robado de thedailywtf.com? :) – JaredPar

+4

Divertido para la referencia de DailyWTF. –

+0

Me gusta la respuesta, pero me gustaría tweek un poco para incluir un valor predeterminado en lugar de FILENOTFOUND, así que publiqué otra versión de la respuesta – Azder

5

Si eso es lo que necesita, cree un valor que represente el concepto de un valor que puede no haberse inicializado.

template <typename T> 
struct Maybe { 
    Maybe() : m_hasValue(false) {} 
    bool HasValue() const { return m_hasValue; } 
    T& Value() { ThrowIfFalse(m_hasValue); return m_value; } 
    const T& Value() const { ThrowIfFalse(m_hasValue); return m_value; } 
    void SetValue(_In_ const T& value) { m_value = value; m_hasValue = true; } 
private: 
    bool m_hasValue; 
    T m_value; 
}; 

Ahora puede representar los 3 estados que necesita.

class SomeType { 
    ... 
    Maybe<bool> m_myBool; 
} 
+2

+1: Sería mejor si C++ tuviera cierres. Supongo que podrías simularlos con punteros de función. (PD: No me gusta el nombre de la clase). –

1

yo no entiendo muy bien, pero lo intentaré ...

valores por defecto se aplica cuando se tiene un inicializador agregado que deja algunos valores no especificado. En ese caso, el valor predeterminado de bool sería falso. En una clase, el valor "predeterminado" no estaría inicializado, lo que significa que podría tener algún valor y podría cambiar de ejecución a ejecución.

Si le interesa saber si un bool ha cambiado o no, su mejor opción es realizar un seguimiento de él con un segundo bool predeterminado en falso, o usar una enumeración que represente 3 estados posibles. Si realmente quieres 3 estados, realmente no quieres un bool.

2

Puede tener un miembro privado separado que indique si el valor de bool se ha inicializado o no.

4

En C++ un bool es solo un bit de información, ya sea un 0 o un 1. Como quiera representar tres posibles estados, necesita un bit más de información. Hay dos técnicas generales:

  1. utilizar otro valor bool para indicar si el valor es "default" o no, o
  2. Uso un tipo de enumeración con tres valores para indicar (por defecto, verdadero, falso).

probablemente elija la opción 1.

18

Parece que usted quiere boost::tribool o tal vez boost::optional<bool>.

+6

Incluso puede configurar boost :: tribool para sus necesidades de DailyWTF: BOOST_TRIBOOL_THIRD_STATE (FILENOTFOUND). –

0

En lugar de un booleano, use una enumeración. Por ejemplo, para controlar el nivel de la magia:

enum { 
    MY_ENUM_NO_MAGIC, 
    MY_ENUM_SOME_MAGIC, 
    MY_ENUM_MORE_MAGIC 
} MagicLevel; 

Después haga que su constructor acepta un parámetro MagicLevel magic = MY_ENUM_NO_MAGIC.

35

Tristate bool es el camino hacia el lado oscuro. Tristate bool conduce a la ira. La ira conduce al odio. El odio lleva al sufrimiento.


prefiere no utilizar un bool de tres estados.

En su lugar, use un booleano adicional para saber si el primer booleano está "inicializado" (o mejor, "conocido") o no.

class Prisoner : public Person 
{ 


    ... 

    bool is_veredict_known; 
    bool is_guilty; 
} 

Si el veredicto no se conoce, sin embargo, no se puede saber si el prisionero es realmente culpable, pero su código puede diferenciar entre las diferentes situaciones. Por supuesto, la Constitución asegura que el valor predeterminado de is_guilty debe ser falsa, pero, aún así ... :)

Por cierto, el invariante de clase debe incluir:

assert(is_veredict_known || !is_guilty); 
1

Realmente no se puede. ¿Podría proporcionar un segundo constructor, por ejemplo:

class MyClass { 
    public: 
    MyClass(bool bFlag); // <-- not default 
    MyClass(void);  // <-- default 
}; 
+0

Esto es similar a lo que ya existía que me dijeron que limpiara :) – voteblake

+0

¿Necesita siquiera exponer el constructor predeterminado? – wreckgar23

+0

No puedo hablar por el póster original, pero, en general, no, no. –

3

Utilice el gran impulso :: opcional. Y no sólo para Bools sino para todos los otros lugares que utilizan algunos valores no inicializados-sucios en Se utiliza la siguiente manera:.

void function(optional<int> value) { 
    if (value) 
     std::cout << "value is defined: " << value.get() << "\n"; 
    else 
     std::cout << "value is not defined\n"; 
} 

y aquí hay un ejemplo de una función que devuelve una opción:

struct MapClass { 
    map<string,int> m_map; 

    optional<int> getValue(string key) { 
     optional<int> result = none; 
     if (m_map.find(key) != m_map.end()) 
     result = m_map[key]; 
     return result; 
    } 
} 
0
class aclass 
{ 
    <stuff> lots of other things 
    bool mybool 
    bool ismyboolinit 

    void setmybool(bool b) 
    { 
     mybool = b; 
     ismyboolinit = true; 
    } 

} 
3
struct Bool { //guaranteed initialized bool 
    bool v; 

    Bool() : v(false) {} 
    operator bool() const { return v; } 
    bool& operator=(const bool val){ return v = val; } 
}; 
0

bien si el uso de las funciones y clases, sólo les sobrecargue.

es decir:

class thing 
{ 
    public: 
    void f1(bool); // bool input 
    void f1(int = 3); // default with out bool being known 
    private: 
    // stuff 
};  
void thing::f1 (bool hasAFace) 
{ 
    if(hasAFace) 
    f1(0); 
    if(!hasAFace) 
    f1(1); 

} 

void thing::f1 (int tri) 
{ 
    bool actionTime; 
    if(tri == 1) 
    actionTime = true; 
    else if(tri == 0) 
    actionTime = false; 
    else 
    //input defualt action here. 
} 

// y ahí lo tienes. Además, no necesitas tener una clase, solo puedes utilizar funciones sobrecargadas.

Cuestiones relacionadas