Best practice in C++ for casting between number types [duplicate]
Asked Answered
C

2

24

What is the best practice for casting between the different number types? Types float, double, int are the ones I use the most in C++.

An example of the options where f is a float and n is a double or an int:

float f = static_cast<float>(n);
float f = float(n);
float f = (float)n;

I usually write static_cast<T>(...) but wondered if there was any consensus within the C++ development community if there is a preferred way.

I appreciate this is may end up being an opinion based question and there may not be a "standard" way, in which case please let me know that there is no standard way so at least I know that :-)

I know this question has cropped up in relation to casting in general, however, I am interested specifically in numbers and whether there are specific best practices in the approach for number types.

Cake answered 28/5, 2016 at 8:47 Comment(6)
Use static_cast, the "standard" C++ way, and nothing changed from C++11 about it.Betthel
The best practice would be to write a program that would not need any castsScamander
float f = n; is my preferenceLightproof
This has not changed in C++11; the same rules apply as under earlier versions of the standard. See linked duplicate question for details, and this one, too.Franni
@Cody Gray, my question is specific to numbers which I'm sure other people may be interested in understanding if the general case applies to. It was not really my intention to imply that I was speculating on whether C++ 11 differs from earlier versions.Cake
@Drop, which only works if you are writing the code from scratch and there are no type differences between third party libraries and you are not using double for accuracy and then floats for vectorization, and many other reasons why casting between numbers is quite typical in scientific computing.Cake
C
17

Just use static_cast. The problem with C casts is the ambiguity of the operation (i.e. point (1) of Explicit type conversion).

C++ casts avoid this. Additionally C++ casts are more visible when searching for them.

Using Stroustrup's words (What good is static_cast?):

Even an innocent-looking cast can become a serious problem if, during development or maintenance, one of the types involved is changed. For example, what does this mean?:

  x = (T)y;

We don't know. It depends on the type T and the types of x and y. T could be the name of a class, a typedef, or maybe a template parameter. Maybe x and y are scalar variables and (T) represents a value conversion. Maybe x is of a class derived from y's class and (T) is a downcast. Maybe x and y are unrelated pointer types. Because the C-style cast (T) can be used to express many logically different operations, the compiler has only the barest chance to catch misuses. For the same reason, a programmer may not know exactly what a cast does. This is sometimes considered an advantage by novice programmers and is a source of subtle errors when the novice guessed wrong.

The "new-style casts" were introduced to give programmers a chance to state their intentions more clearly and for the compiler to catch more errors.

[CUT]

A secondary reason for introducing the new-style cast was that C-style casts are very hard to spot in a program. For example, you can't conveniently search for casts using an ordinary editor or word processor.

[CUT]

casts really are mostly avoidable in modern C++

Also consider boost::numeric::converter / boost::numeric_cast that are safer alternatives (part of Boost.NumericConversion library).

E.g.

#include <iostream>
#include <boost/numeric/conversion/cast.hpp>

int main()
{
  using boost::numeric_cast;

  using boost::numeric::bad_numeric_cast;
  using boost::numeric::positive_overflow;
  using boost::numeric::negative_overflow;

  try
  {
    int i = 42;
    short s = numeric_cast<short>(i); // This conversion succeeds (is in range)
  }
  catch(negative_overflow &e)  { std::cout << e.what(); }
  catch(positive_overflow &e)  { std::cout << e.what(); }

  return 0;
}

In general for both implicit conversions and explicit conversions (through static_cast) the lack of preservation of range makes conversions between numeric types error prone.

numeric_cast detects loss of range when a numeric type is converted and throws an exception if the range cannot be preserved.

Cherry answered 28/5, 2016 at 8:57 Comment(4)
"sometimes it's a conversion ... sometimes it's a cast" doesn't make much sense to me. A cast is an explicit conversion, is it not?.Gantlet
@user2079303 You are right: it's "Google's terminology" (google.github.io/styleguide/cppguide.html#Casting) but it doesn't exactly match regular C++ usage (https://mcmap.net/q/16828/-type-conversion-casting-confusion-in-c/3235496). I've change that line to avoid misunderstandings.Cherry
Thanks for the link. It will help when I stumble on that terminology in future. Too bad the guide doesn't explain the difference between a cast and a conversion in their terminology.Gantlet
@Cherry if boost is not an option, here is a re-implementation of boost::numeric_cast using only code available in std library: https://mcmap.net/q/583742/-does-c-have-an-equivalent-to-boost-numeric_cast-lt-desttype-gt-sourcetypeDagley
C
-2

Generally, these casting operators are classified under two major groups: specific casting operators and traditional casting operators. cplusplus.com explains it like this:

...In order to control these types of conversions between classes, we have four specific casting operators: dynamic_cast, reinterpret_cast, static_cast and const_cast. Their format is to follow the new type enclosed between angle-brackets (<>) and immediately after, the expression to be converted between parentheses.

dynamic_cast <new_type> (expression)

reinterpret_cast <new_type> (expression)

static_cast <new_type> (expression)

const_cast <new_type> (expression)

The traditional type-casting equivalents to these expressions would be:

(new_type) expression

new_type (expression)

but each one with its own special characteristics.

While working on a task, we (nearly) all use specific casting. After considering the advises, it's up to you somehow.

See the resource.

Complain answered 28/5, 2016 at 9:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.