I am aware that the different casting operators in C++ have already been discussed here many times but my question is specifically about casting between numeric types, not about the general differences between C style and C++ style operators. I consider this a completely different topic than casting within a class hierarchy.
Say I want to cast an int i
to a double, some of the options I have are
static_cast<double>(i)
(double) i
double(i)
Personally I prefer the constructor-like style in the 3rd line in this case because I like to express that this is not a cast beteen class types, where I would certainly use static_cast
or dynamic_cast
.
Except from making it difficult to find this type of cast when searching in a text editor, are there any drawbacks of my choice?
static_cast<double>(i)
is certainly the clearest expression of your intent in this particular case.
When casting between numeric types, you are often a stone's throw away from undefined behaviour. So be careful in general. Although your cast is defined for every possible value of i
, casting a double
to an int
could overflow the int
, and that behaviour is undefined in C++.
I would always advise your checking if the destination type can accommodate the source type. std::numeric_limits<>::max()
etc. can help here.
The C++ standard does not specify a maximum size of int
(although 16, 32, and 64 bit 2's complement are common), so, potentially it might not be representable as a double
.
In my code I have a namespace containing
template<
typename T/*the desired type*/,
typename/*the source type*/ Y
> T integral_cast(const Y& y)
{
static_assert(false, "undefined integral_cast");
}
which I specialise for every numeric cast I need.
One major drawback of those approaches is the cast is not safe against overflows, and other numeric errors.
Using static_cast
is the immediate sane solution and this method is not flagged by static code analysts tools like PVS studio. the (double)i
approach generates a warning.
Probably the safest approach is to have your own cast let's say numeric_cast<T>()
template <class OT, class ST>
OT numeric_cast(const ST value)
{
return static_cast<OT>(value);
}
The advantage of this function is that you can do bound checks and other numeric checks to ensure that the cast is legitimate and does not return (or get) junk values.
There is another way of dealing with numbers but it only work with constant compile-time values. For this check user defined string literals
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With