diff --git a/book/hello.Rmd b/book/hello.Rmd index 5edef9e..9d8559f 100644 --- a/book/hello.Rmd +++ b/book/hello.Rmd @@ -25,12 +25,8 @@ Every C++ executable (as opposed to library) must have a `main()` function that returns `int`. Returning `0` signifies that the program terminates without errors. The final `return 0;` statement can be omitted in the `main()` function. -`#include` is a preprocessor. We'll meet more preprocessors in the future, for now - just accept that they are "naive macros" that are "expanded" before the actual - compilation. -Here `#include` copies the content of file called `iostream`, which has tens of -thousands lines, and pastes it here. Yes, it literally does so, and you can check -this by running `g++ -E main.c`, which "expands" all preprocessor statements. +`#include` is a preprocessor directive. We'll learn more about the preprocessor in later chapters, for now just accept that preprocessor directives are "naive macros" that are "expanded" before the actual compilation. +Here `#include` copies the content of file called `iostream`, which has tens of thousands lines, and pastes it here. Yes, it literally does so, and you can check this by running `g++ -E main.c`, which "expands" all preprocessor statements. `iostream` contains definitions of functions and objects such as `std::cout` and `std::endl`, which are used for IO manipulations. `cout` stands for "character @@ -131,7 +127,7 @@ int a{5}; knitr::include_graphics("img/equal.png") ``` -If you try `int a{5.5};` with this syntax, the compiler will give an error and abort (Figure \@ref(fig:braces) ). In addition, you can't separate the two parts: +If you try `int a{5.5};` with this syntax, the compiler will give an error and abort (Figure \@ref(fig:braces) ). In addition, you can't separate the two parts, thus enforcing that variables are not left uninitialized: ```c++ // not allowed @@ -145,6 +141,30 @@ knitr::include_graphics("img/brace.png") Of course, the uniform initialization syntax isn't invented just to prevent implicit conversion. As you'll see later, it can become handy when initializing complicated, non-primitive data types. +###`auto` vs `let` + +Another key difference with declaring / initializing variables is in how types are inferred. In C++, the type of a variable can be inferred by replacing the type name with `auto`: + +```c++ +//These lines are equivalent +auto a = 5; +int a = 5; +``` + +Unlike Rust's `let` keyword, a variable declared with `auto` MUST be initialized in the same statement - that is, you cannot declare the variable with `auto`, then have the compiler infer the type from an initialization in another statement. Example: + +```rust +// Rust - valid, type of a will be inferred as f32 +let a; +a = 10. as f64; +``` + +```c++ +// C++ - invalid, variable must be initialized and declared in the same statement +auto a; +a = 10.; +``` + ### Mutability Variables are mutable by default. If you want to create an immutable variable, use the `const` keyword. @@ -752,4 +772,4 @@ int& rj = j; ri = rj; // What are the values of i, j, ri and rj now? // Hint: a reference cannot be re-assigned. What's the last line doing? -``` \ No newline at end of file +```