Invalid values
In code it's often natural to have (invalid) default values for initialization and (debug) checking. For example an enum in C++:
enum Color
{
eClrUndefined = -1,
eClrRed = 0,
eClrGreen,
};
class Ball
{
Color m_eClr = eClrUndefined;
};
Identifier
For object identifiers a long can be used. For example:
using PersonId = long;
constexpr PersonId g_idInvalid = -1;
Code can test for validity of the id and checking against an invalid value:
const PersonId id = LookupPersonId(...);
if (id != g_idInvalid)
{
//...
}
Alternative ways of signaling invalid values are e.g.
std::optional
but reserving a special value is more compact.
Double
For doubles it would be natural to use a NaN as invalid default value since NaN's stay invalid when used in (accidental) calculations. Suppose:
#include <limits>
using Distance = double;
constexpr Distance g_dInvalid = std::numeric_limits<Distance>::signaling_NaN();
Checking against invalid becomes a hindrance now since NaN's never check equal
against another NaN or any other number. This gives already issues when
defining the equality operator which could be solved by adding an extra case
for NaN:
#include <cmath>
#include <limits>
class Quantity
{
bool operator==(const Quantity& rRhs) const noexcept
{
if (std::isnan(m_dValue))
{
return std::isnan(rRhs.m_dValue);
}
else
{
return m_dValue == rRhs.m_dValue;
}
}
double m_dValue = std::numeric_limits<double>::signaling_NaN();
};
Alternatives might therefore be more appropriate:
- max or an other unreachable value
std::optional
- use a function e.g.
IsInvalidDistance
which usesisnan
.
Note that exact equality checking of floating point numbers is room for another topic.
No comments:
Post a Comment