Chapter 14: Conversion and Alias

Conversion

Implicit Conversion

Implicit conversions are automatically performed by the compiler when needed.

double d{ 3 }; // int value 3 implicitly converted to type double
float doSomething() { return 3.0; } // double value 3.0 implicitly converted to type float
double division{ 4.0 / 3 }; // int value 3 implicitly converted to type double
if (5) {} // int value 5 implicitly converted to type bool
void doSomething(long l) {} doSomething(3); // int value 3 implicitly converted to type long

short s{ 3 }; // there is no short literal suffix, so we'll use a variable for this one
printInt(s); // numeric promotion of short to int
printInt('a'); // numeric promotion of char to int
printInt(true); // numeric promotion of bool to int
printDouble(4.0f); // numeric promotion of float to double

Note: A wider data type uses more bits, and a narrower data type uses fewer bits.

Numeric Promotion

Example of Narrowing Conversion

constexpr int n1{ 5 };   // note: constexpr
unsigned int u1 { n1 };  // okay: conversion is not narrowing due to exclusion clause
constexpr int n2 { -5 }; // note: constexpr
unsigned int u2 { n2 };  // compile error: conversion is narrowing due to value change

int x { 3.5 }; // brace-initialization disallows conversions that result in data loss

Floating Point Promotions

double d = 10 / 4; // does integer division, initializes d with value 2.0
double d = 10.0 / 4.0; // does floating point division, initializes d with value 2.5

Type Casting

(int)d               // C-style cast, avoid using C-style casts.
int(d)               // C++ version of C-style cast
static_cast(d)  // C++-style cast

Using typeid

#include <typeinfo> // for typeid()
typeid(i + d).name()

std::cout << typeid(5u - 10).name() << ' ' << 5u - 10 << '\n'; // 5u means treat 5 as an unsigned integer

Summary

Alias

using Distance = double; // define Distance as an alias for type double
Distance milesToDestination{ 3.4 }; // defines a variable of type double

Example with Header File

// file.h
#ifndef MYTYPES_H
#define MYTYPES_H

using Miles = long;
typedef long Miles; // same
using Speed = long;

#endif

Using Proper Types

#ifdef INT_2_BYTES
using int8_t = char;
using int16_t = int;
using int32_t = long;
#else
using int8_t = char;
using int16_t = short;
using int32_t = int;
#endif

using VectPairSI = std::vector<std::pair<std::string, int>>; // make VectPairSI an alias for this crazy type

Using auto

The auto keyword allows the compiler to deduce the type of a variable from its initializer.

auto var{10};
auto sum { func(5, 6) }; // func() returns an int, so sum's type will be deduced to int

auto s { "Hello, world" }; // s will be type const char*, not std::string
using namespace std::literals; // easiest way to access the s and sv suffixes
auto s1 { "goo"s };  // "goo"s is a std::string literal, so s1 will be deduced as a std::string
auto s2 { "moo"sv }; // "moo"sv is a std::string_view literal, so s2 will be deduced as a std::string_view

auto foo() { return 5; } // no forward declaration for auto
auto add(int x, int y) -> int // trailing return syntax
{
    return (x + y);
}