Ready to practice?
Sign up to access interactive coding exercises and track your progress.
Automatic Type Conversions in C++
Understand when the compiler automatically converts between types and potential pitfalls.
Implicit Type Conversion
We introduced type conversion in an earlier lesson. Let's recap the most important points:
- The process of converting data from one type to another is called "type conversion"
- Implicit type conversion is performed automatically by the compiler when one data type is required but a different data type is supplied
- Explicit type conversion is requested using a cast operator, such as
static_cast - Conversions don't change the data being converted. Instead, the conversion process uses that data as input and produces a converted result
- When converting a value to another type, the conversion process produces a temporary object of the target type holding the result
In the first half of this chapter, we'll dig deeper into how type conversion works. We'll start with implicit conversions in this lesson, and explicit type conversions (casting) in an upcoming lesson. Since type conversion is used extensively, understanding what happens under the hood when a conversion is needed is important. This knowledge is also relevant for understanding how overloaded functions (functions that can have the same name as other functions) work.
In this chapter, we'll focus on converting values to other value types. We'll cover other conversion types once we introduce prerequisite topics (such as pointers, references, inheritance, etc.).
Why Conversions Are Needed
An object's value is stored as a sequence of bits, and the object's data type tells the compiler how to interpret those bits into meaningful values. Different data types may represent the "same" value differently. For example, integer value 7 might be stored as binary 0000 0000 0000 0000 0000 0000 0000 0111, whereas floating point value 7.0 might be stored as binary 0100 0000 1110 0000 0000 0000 0000 0000.
So what happens when we do something like this?
float temperature{ 7 }; // initialize floating point variable with int 7
In such a case, the compiler can't just copy the bits used to represent int value 7 into the memory allocated for float variable temperature. If it did, then when temperature (which has type float) was evaluated, those bits would be interpreted as a float rather than an int, and who knows what float value we'd end up with!
Instead, integer value 7 needs to be converted into the equivalent floating point value 7.0, which can then be stored in the memory allocated for temperature (using the bit representation for float value 7.0).
When Implicit Type Conversion Happens
Implicit type conversion (also called automatic type conversion or coercion) is performed automatically by the compiler when an expression of some type is supplied in a context where some other type is expected. The vast majority of type conversions in C++ are implicit type conversions. For example, implicit type conversion happens in all these cases:
When initializing (or assigning a value to) a variable with a value of a different data type:
double roomTemp{ 72 }; // int value 72 implicitly converted to type double
roomTemp = 98; // int value 98 implicitly converted to type double
When the return value type differs from the function's declared return type:
float performCalculation()
{
return 3.0; // double value 3.0 implicitly converted to type float
}
When using certain binary operators with operands of different types:
double result{ 8.0 / 3 }; // int value 3 implicitly converted to type double
When using a non-Boolean value in an if-statement:
if (5) // int value 5 implicitly converted to type bool
{
}
When an argument passed to a function is a different type than the function parameter:
void displayMessage(long messageId)
{
}
displayMessage(3); // int value 3 implicitly converted to type long
So how does the compiler know how to convert a value to a different type?
The Standard Conversions
As part of the core language, the C++ standard defines a collection of conversion rules known as "standard conversions". The standard conversions specify how various fundamental types (and certain compound types, including arrays, references, pointers, and enumerations) convert to other types within that same group.
As of C++23, there are 14 different standard conversions. These can be roughly grouped into 5 general categories:
| Category | Meaning |
|---|---|
| Numeric promotions | Conversions of small integral types to int or unsigned int, and of float to double |
| Numeric conversions | Other integral and floating point conversions that aren't promotions |
| Qualification conversions | Conversions that add or remove const or volatile |
| Value transformations | Conversions that change the value category of an expression |
| Pointer conversions | Conversions from std::nullptr to pointer types, or pointer types to other pointer types |
For example, converting an int value to a float value falls under the numeric conversions category, so the compiler simply needs to apply the int to float numeric conversion rules to perform such a conversion.
The numeric conversions and numeric promotions are the most important of these categories, and we'll cover them in more detail in upcoming lessons.
Type Conversion Can Fail
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.
If the compiler can't find an acceptable conversion, then the compilation 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.
For example:
int main()
{
int value{ "42" };
return 0;
}
Because there isn't a standard conversion from the string literal "42" to int, the compiler will produce an error. For example, GCC produces the error: error: invalid conversion from 'const char*' to 'int'.
In other cases, specific features may disallow some categories of conversions. For example:
int value{ 3.5 }; // brace-initialization disallows conversions that result in data loss
Even though the compiler knows how to convert a double value to an int value, narrowing 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 the best one to use. We'll see examples of this in a later lesson on function overload resolution.
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 the standard conversions.
Let's get started!
Summary
Type conversion: The process of converting data from one type to another. Implicit type conversion is performed automatically by the compiler, while explicit type conversion uses cast operators.
Why conversions are needed: Different data types represent values using different bit patterns. Converting between types requires creating a new value with the appropriate bit representation for the target type.
When implicit conversion happens: Implicit conversions occur during initialization, function returns, binary operations with mixed types, conditionals, and function calls when argument types differ from parameter types.
Standard conversions: The C++ standard defines 14 standard conversions grouped into numeric promotions, numeric conversions, qualification conversions, value transformations, and pointer conversions.
Type conversion can fail: The compiler produces an error if it cannot find an acceptable conversion, such as when no conversion exists between types or when conversions are disallowed (like narrowing conversions in brace initialization).
Temporary objects: Type conversions produce temporary objects of the target type holding the converted value. The original value remains unchanged.
Understanding implicit type conversion is fundamental to C++ programming. While the compiler handles most conversions automatically, knowing when and how conversions occur helps you write correct code and understand compiler errors when conversions fail.
Automatic Type Conversions in C++ - Quiz
Test your understanding of the lesson.
Practice Exercises
Understanding Implicit Type Conversion
Explore how C++ automatically converts between types. Learn about numeric promotions, conversions, and potential pitfalls.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!