Variables, Scopes and Namespaces: Uniform Initialization#

Adapted from: “Learn Modern C++” by cpptutor: Learn Modern C++: Variables, Scopes and Namespaces

Program that Demonstrates Uniform Initialization#

// 02-uniform.cpp : avoid compiler error with uniform initialization and explicit narrowing cast
 
#include <print>
using namespace std;
 
int main() {
    // int c = { 2.5 };                 // Error: this does NOT compile
    int c = { static_cast<int>(2.5) };  // while this does
    double d = { 1 };                   // and so does this
    println("c = {}, d = {}", c, d);
}

Explanation of the Above Code#

This C++ code demonstrates uniform initialization and the use of explicit narrowing casts to avoid compiler errors. Here’s a breakdown:

Code Explanation:#

  1. Header Inclusion:

    #include <print>
    
    • The <print> header is part of the C++23 standard library. It provides the println function, which is used for formatted output, similar to Python’s print.

  2. Namespace:

    using namespace std;
    
    • This allows the program to use standard library features (like println) without needing to prefix them with std::.

  3. Main Function:

    int main() {
    
    • The main function is the entry point of the program.

  4. Uniform Initialization:

    int c = { 2.5 };                 // Error: this does NOT compile
    
    • Uniform initialization (using curly braces {}) enforces stricter type checking.

    • Here, assigning a double value (2.5) to an int variable (c) causes a compiler error because it involves narrowing conversion (loss of precision).

  5. Explicit Narrowing Cast:

    int c = { static_cast<int>(2.5) };  // while this does
    
    • The static_cast<int>(2.5) explicitly converts the double value 2.5 to an int (truncating the decimal part). This resolves the compiler error.

  6. Another Example of Uniform Initialization:

    double d = { 1 };                   // and so does this
    
    • Assigning an int value (1) to a double variable (d) is allowed because it does not involve narrowing conversion.

  7. Formatted Output:

    println("c = {}, d = {}", c, d);
    
    • The println function outputs the values of c and d in a formatted string. The placeholders {} are replaced with the values of c and d.

Output:#

When executed, the program will output:

c = 2, d = 1

Key Concepts:#

  • Uniform Initialization: Enforces stricter type checking and prevents implicit narrowing conversions.

  • Explicit Narrowing Cast: Use static_cast to explicitly convert types when narrowing is necessary.

  • Formatted Output: The println function simplifies printing formatted strings in C++23.

Compile and Run Code#

Use Python to Change to Working Directory#

import os
root_dir = os.getcwd()
code_dir = root_dir + "/" + "Cpp_Code/02_Variables_Scopes_and_Namespaces"
os.chdir(code_dir)

Use Docker to Compile the Code in a C++23 Environment#

!docker run --rm -v $(pwd):/app cpp23-clang18:latest clang++-18 -std=c++23 -stdlib=libc++ /app/02-uniform.cpp -o /app/02-uniform

Use Docker to Run Executable in a C++23 Environment#

!docker run --rm -v $(pwd):/app cpp23-clang18:latest ./02-uniform
c = 2, d = 1