I'm redesigning a class constructor in C++ and need it to catch an unspecified bool. I have used default values for all of the other parameters, but from my understanding bool can only be initialized to true or false. Since both of those cases have meaning in the class, how should I handle checking for change from a default value?
If that's what you need, create a value which represents the concept of a value that may not have been initialized.
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;
};
Now you can represent all 3 states you need.
class SomeType {
...
Maybe<bool> m_myBool;
}
I don't quite understand, but I'll try...
Default values are applied when you have an aggregate initializer that leaves some values unspecified. In that case, bool's default would be false. In a class, the "default" value would be uninitialized, meaning it could be any value and could change from run to run.
If you're interested in whether or not a bool has changed, your best option is to keep track of it with a second bool defaulting to false, or use an enum representing 3 possible states. If you truly want 3 states, you really don't want a bool.
Hi
I guess bool is uninitialized by default and remains so until you assign a value (true/false) to it
cheers
You could have a separate private member that indicates whether the bool value has actually been initialized or not.
In C++ a bool
is only one bit of information, either a 0 or a 1. Since you want to represent three possible states, you need one more bit of information. There are two general techniques:
- Use another
bool
value to indicate whether the value is "default" or not, or - Use an enumeration type with three values to indicate (default, true, false).
I would probably choose option 1.
It sounds like you want boost::tribool or maybe boost::optional<bool>.
The reality is that you can't do this. A bool has value, either true or false, and if you haven't initialized it then it is randomly true or false, possibly different at each run of the program or allocation of that class.
If you need to have a type with more options, define an enum.
typedef enum MyBool {
TRUE,
FALSE,
FILENOTFOUND
} MyBool;
Instead of a boolean, use an enumeration. For example, to control the level of magic:
enum {
MY_ENUM_NO_MAGIC,
MY_ENUM_SOME_MAGIC,
MY_ENUM_MORE_MAGIC
} MagicLevel;
Then have your constructor accept a parameter MagicLevel magic = MY_ENUM_NO_MAGIC
.
I like the enum version answers, but I usually like adding some null value, and also in this case you could use a default one too. Example:
typedef enum {
// Uncomment if you want a null value possible
// NONE -1,
// You could use c++ value for TRUE instead of 1
TRUE = 1,
// You could use c++ value for FALSE instead of 1
FALSE = 0,
/*
You could initialize DEFAULT
to TRUE or FALSE,
but then you marry that value
for future versions of the interface
*/
DEFAULT
} MYBOOL ;
Tristate bool is the path to the dark side. Tristate bool leads to anger. Anger leads to hate. Hate leads to suffering.
In other words, prefer not to use a tristate bool.
Instead, use one additional boolean for whether the first boolean is "initialized" (or better, "known") or not.
class Prisoner : public Person
{
...
bool is_veredict_known;
bool is_guilty;
}
If the veredict is not known yet, you can't tell if the Prisoner is really guilty, but your code can differentiate between the different situations. Of course the Constitution assures that the default value of is_guilty should be false, but, still... :)
By the way, the class invariant should include:
assert(is_veredict_known || !is_guilty);
You really can't. Could you provide a second constructor, for example:
class MyClass {
public:
MyClass(bool bFlag); // <-- not default
MyClass(void); // <-- default
};
Use the great boost::optional. And not only for bools but for all other places you used some dirty not-initialized-values in. It is used like this:
void function(optional<int> value) {
if (value)
std::cout << "value is defined: " << value.get() << "\n";
else
std::cout << "value is not defined\n".
}
And here's a function example returning an optional:
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;
}
}
class aclass
{
<stuff> lots of other things
bool mybool
bool ismyboolinit
void setmybool(bool b)
{
mybool = b;
ismyboolinit = true;
}
}
struct Bool { //guaranteed initialized bool bool v;
Bool() : v(false) {}
operator bool() const { return v; }
bool& operator=(const bool val){ return v = val; }
};