Search

8.1 — Implicit type conversion (coercion)

Introduction to type conversion

The value of an object is stored as a sequence of bits, and the data type of the object tells the compiler how to interpret those bits into meaningful values. Different data types may represent the “same” number differently. For example, the integer value 3 might be stored as binary 0000 0000 0000 0000 0000 0000 0000 0011, whereas floating point value 3.0 might be stored as binary 0100 0000 0100 0000 0000 0000 0000 0000.

So what happens when we do something like this?

In such a case, the compiler can’t just copy the bits representing the int value 3 into the memory allocated for float variable f. Instead, it needs to convert the integer value 3 to the equivalent floating point number, which can then be stored in the memory allocated for f.

The process of converting a value from one data type to another data type is called a type conversion.

Type conversion can be invoked in one of two ways: either implicitly (as needed by the compiler), or explicitly (when requested by the programmer). We’ll cover implicit type conversion in this lesson, and explicit type conversions (casting) in upcoming lesson 8.5 -- Explicit type conversion (casting) and static_cast.

Implicit type conversion

Implicit type conversion (also called automatic type conversion or coercion) is performed automatically by the compiler when one data type is required, but a different data type is supplied. The vast majority of type conversions in C++ are implicit type conversions. For example, implicit type conversion happens in all of the following cases:

When initializing (or assigning a value to) a variable with a value of a different data type:

When the type of a return value is different from the function’s declared return type:

When using certain binary operators with operands of different types:

When using a non-Boolean value in an if-statement:

When an argument passed to a function is a different type than the function parameter:

What happens when a type conversion is invoked

When a type conversion is invoked (whether implicitly or explicitly), the compiler will determine whether it can convert the value from the current type to the desired type. If a valid conversion can be found, then the compiler will produce a new value of the desired type. Note that type conversions don’t change the value or type of the value or object being converted.

If the compiler can’t find an acceptable conversion, then the compile will fail with a compile error. Type conversions can fail for any number of reasons. For example, the compiler might not know how to convert a value between the original type and the desired type. In other cases, statements may disallow certain types of conversions. For example:

Even though the compiler knows how to convert a double value to an int value, such conversions are disallowed when using brace-initialization.

There are also cases where the compiler may not be able to figure out which of several possible type conversions is unambiguously the best one to use. We’ll see examples of this in lesson 8.11 -- Function overload resolution and ambiguous matches.

So how does the compiler actually determine whether it can convert a value from one type to another?

The standard conversions

The C++ language standard defines how different fundamental types (and in some cases, compound types) can be converted to other types. These conversion rules are called the standard conversions.

The standard conversions can be broadly divided into 4 categories, each covering different types of conversions:

When a type conversion is needed, the compiler will see if there are standard conversions that it can use to convert the value to the desired type. The compiler may apply zero, one, or more than one standard conversions in the conversion process.

As an aside...

How do you have a type conversion with zero conversions? As an example, on architectures where int and long both have the same size and range, the same sequence of bits is used to represent values of both types. Therefore, no actual conversion is needed to convert a value between those types -- the value can simply be copied.

The full set of rules describing how type conversions work is both lengthy and complicated, and for the most part, type conversion “just works”. In the next set of lessons, we’ll cover the most important things you need to know about type conversions. If finer detail is required for some uncommon case, the full rules are detailed in technical reference documentation for implicit conversions.

Let’s get to it!


8.2 -- Floating-point and integral promotion
Index
7.x -- Chapter 7 summary and quiz

150 comments to 8.1 — Implicit type conversion (coercion)

  • What is the difference of significant and precision on floating points like float/double?

    • what I didnt get what you said but here is a definition of significant digits in wiki
      https://en.wikipedia.org/wiki/Significant_figures#Rules_to_identify_significant_figures_in_a_number

      A float if i remember right can only be precise up to 6 significant digits
      A double can be precise up to 16 significant digits

  • james

    "In all cases, converting a value into a type that doesn’t have a large enough range to support the value will lead to unexpected results."

    As far as I'm concerned, this one is not quite true. Unsigned integer overflow is always well-defined, because unsigned integers wrap around. Consider the following example:

    Negative integers can also be converted to unsigned integers, and behavior is still well-defined.

    Signed integer representation is not defined by the standard (actually, hasn't been defined until recently), so signed overflow is not well-defined (does not wrap around).
    Please correct me if I'm wrong!

    • nascardriver

      "well-defined" doesn't mean "expected". Yes you can do what you did and the results will be what you predicted*, but you'll find many developers who wouldn't expect these results, or think they're implementation-defined.
      If you want to use the built-in wrap-around while initializing a variable, it's better to be explicit about it by using a `static_cast`. That way the reader knows you're intentionally discarding data.
      Even better, use modulus so that the reader doesn't have to know conversion rules.

      *an `unsigned char` can be wider than 8 bits, giving you other results than you expected, surprise

  • Chayim

    Why does this code not work?

  • Forhad Rahman

    My compiler is showing 'i' instead of 'int'. That's okay. But I didn't include <typeinfo> in header. Despite, it's showing the type.

    Is it normal?

  • Gwennan

    "promotions generally involve extending the binary representation of a number (e.g. for integers, adding leading 0s)"

    Just wanted to  point out that it's true that promotion for unsigned integers is adding leading 0s, but for signed I'd say we need to add leading 1s in order to make the promotion when the number is negative, and 0s if it's non-negative.

  • Alan LAI

    I find an good example of numeric conversions is converting int to char

  • Muscaria

    J34NP3T3R,

    I'm guessing that they do that in order to ensure that when these values are operated on the result will have sufficient space. It isn't really checking the size of what the short ints contain. It's just a safety feature. Again, that is just my speculation.

  • bob

    I think a note should be added in regards to the "." operator instead of just thrusting it in our faces without assuming we've magically heard of it before when it hasn't even been mentioned yet.

  • SuperNoob

    Wanted to resolve input type in the runtime but failed hilariously :D Cause once the auto type is initialized with a literal, that "auto" type gains the type of that literal. So there's no way to resolve input type in this SuperNoob method :')

    Sample Output:

    Enter anything: asdf
    double

  • J34NP3T3R

    in this example ;

    int main()
    {
        short a{ 4 };
        short b{ 5 };
        std::cout << typeid(a + b).name() << ' ' << a + b << '\n'; // show us the type of a + b

        return 0;
    }
    Because shorts are integers, they undergo integral promotion to ints before being added. The result of adding two ints is an int, as you would expect:

    why does integral promotion happen when both a and b are of the same type and the result is also within range of "short" ?

Leave a Comment

Put all code inside code tags: [code]your code here[/code]