Best practice in C++ for casting between number types

12,778

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.

Share:
12,778

Related videos on Youtube

keith
Author by

keith

Updated on June 15, 2022

Comments

  • keith
    keith almost 2 years

    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.

    • Ivan Aksamentov - Drop
      Ivan Aksamentov - Drop almost 8 years
      The best practice would be to write a program that would not need any casts
    • keith
      keith almost 8 years
      @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.
    • keith
      keith almost 8 years
      @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.
    • Cody Gray
      Cody Gray
      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.
  • eerorika
    eerorika almost 8 years
    "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?.
  • manlio
    manlio almost 8 years
    @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 (stackoverflow.com/q/4337306/3235496). I've change that line to avoid misunderstandings.
  • eerorika
    eerorika almost 8 years
    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.
  • Trevor Boyd Smith
    Trevor Boyd Smith almost 6 years
    @manlio if boost is not an option, here is a re-implementation of boost::numeric_cast using only code available in std library: stackoverflow.com/a/49658950/52074

Related