C++ Complete Course — CodeStudio Vault
0 / 36 topics
C++ Fundamentals

Complete C++ Reference Course

From variables and arrays to classes, loops, and the preprocessor — every concept explained line-by-line with real code, clear steps, and interactive progress tracking. No need to go anywhere else.

7Modules
36Topics
C++11+Standard
100%Free
Overall Progress — 0 of 36 topics completed
0Completed
36Remaining
0%Progress
01
Module 1 — Getting Started
Variables, data types, input/output, references, namespaces
0% · 0/6 done
1.1 — Hello World & Compilation
Expand →

What is this?

Every C++ journey starts with a simple program that prints text to the screen. You write the code in a .cpp file, compile it with a compiler (like g++), and run the output binary. The #include <iostream> directive imports the Input/Output stream library, and std::cout is the standard output object used to print.

1Write your first C++ file (hello.cpp)
hello.cpp
#include <iostream>

int main() {
 std::cout << "Hello QuickRef\n";
 return 0;
}
2Compile and run from the terminal
Terminal
# Compile: g++ takes source file, -o sets output name
$ g++ hello.cpp -o hello

# Run the compiled binary
$ ./hello
Hello QuickRef

main() is the entry point of every C++ program. It must return an int. Returning 0 signals success to the operating system. The \n inside the string is a newline character.

1.2 — Variables & Data Types
Expand →

What is a Variable?

A variable is a named container that stores a value in memory. Every variable has a data type that tells the compiler what kind of data it holds (numbers, text, true/false, etc.). You declare a variable by writing: type name = value;

1Declaring and initializing variables
C++
int number = 5; // Integer — whole numbers
float f = 0.95; // Float — decimal, ~7 digits precision
doublePI = 3.14159; // Double — decimal, ~15 digits precision
char yes = 'Y'; // Char — single character (use single quotes)
std::string s = "ME"; // String — text (use double quotes)
bool isRight = true; // Bool — true or false only

// Constants: value can never be changed after declaration
const floatRATE = 0.8; // Convention: UPPER_CASE for constants

// Modern C++11 brace-initialization syntax
int age {25};
std::cout << age; // Prints: 25
2Primitive Data Types — sizes and ranges
Data TypeSizeRange / Notes
int4 bytes-2,147,483,648 to 2,147,483,647
float4 bytes~7 significant decimal digits
double8 bytes~15 significant decimal digits
char1 byte-128 to 127 (stores one character)
bool1 bytetrue (1) or false (0)
voidN/ARepresents no value / no type
wchar_t2 or 4 bytesWide character (Unicode support)

Use double over float by default — it is more precise and modern CPUs handle both at the same speed. Use float only when memory is a tight constraint (e.g., game development, embedded systems).

1.3 — User Input (cin) & swap()
Expand →

Input & Utility Functions

std::cin reads user input from the keyboard and stores it in a variable. The >> operator extracts (reads) from the input stream. std::swap() is a standard utility that exchanges the values of two variables in one line.

1Reading user input with cin
C++
int num;

std::cout << "Type a number: ";
std::cin >> num; // Reads integer from keyboard into num

std::cout << "You entered " << num;
2Swapping two variables
C++
int a = 5, b = 10;
std::swap(a, b); // Exchanges values of a and b

// Output: a=10, b=5
std::cout << "a=" << a << ", b=" << b;

std::cout and std::cin use the extraction (>>) and insertion (<<) operators. You can chain multiple outputs: cout << a << " " << b;

1.4 — Comments
Expand →

What are Comments?

Comments are notes for human readers — the compiler completely ignores them. Use them to explain why you wrote something, or to temporarily disable code. C++ has two styles: single-line (//) and multi-line (/* */).

C++
// This is a single-line comment — everything after // is ignored

/* This is a multi-line comment.
 It can span many lines.
 Useful for longer explanations. */

int x = 5; // inline comment — after the code on the same line

Good code is self-documenting. Write comments to explain the reason behind a decision, not just what the code does. Avoid: // add 1 to i. Prefer: // skip the header row.

1.5 — References
Expand →

What is a Reference?

A reference is an alias — another name for an existing variable. Both the original and the reference point to the same memory address, so changing one changes the other. References are declared using the & symbol after the type.

C++
int i = 1;
int& ri = i; // ri is a reference (alias) to i
 // ri and i now share the SAME memory location

ri = 2; // Changes ri → also changes i (same memory!)
std::cout << "i=" << i; // Prints: i=2

i = 3; // Changes i → also changes ri
std::cout << "ri=" << ri; // Prints: ri=3

References must be initialized when declared — you cannot have a reference that points to nothing. This is different from pointers which can be null.

1.6 — Namespaces
Expand →

What is a Namespace?

A namespace is a named scope that groups related identifiers (functions, classes, variables) to avoid name conflicts. The C++ standard library lives in the std namespace — that's why you write std::cout. You can bring names into scope with using namespace, or create your own namespace with namespace myName { ... }.

1Creating and using a custom namespace
C++ — With scope operator
#include <iostream>

namespace ns1 {
 int val() { return 5; } // function inside namespace ns1
}

int main() {
 std::cout << ns1::val(); // Access using :: scope operator → prints 5
}
2Using "using namespace" to skip the prefix
C++ — With using directive
#include <iostream>

namespace ns1 { int val() { return 5; } }

using namespace ns1; // Now val() is directly accessible
using namespace std; // Now cout, cin etc. work without std::

int main() {
 cout << val(); // No std:: or ns1:: prefix needed — prints 5
}

using namespace std; is convenient for small programs but can cause name conflicts in large codebases. In professional code, prefer explicit std:: prefixes.

02
Module 2 — Arrays
Declaration, manipulation, displaying, multidimensional arrays
0% · 0/4 done
2.1 — Array Declaration & Initialization
Expand →

What is an Array?

An array is a fixed-size collection of elements of the same type, stored in contiguous memory. In C++11+, prefer std::array over C-style arrays — it's safer and has built-in size awareness. Elements are accessed by zero-based index: arr[0] is the first element.

C++
#include <array>

// Step 1: Declare empty array of 3 integers, then assign
std::array<int, 3> marks;
marks[0] = 92;
marks[1] = 97;
marks[2] = 98;

// Step 2: Declare AND initialize at once (cleaner)
std::array<int, 3> scores = {92, 97, 98};

// Step 3: Partial init — missing elements default to 0
std::array<int, 3> partial = {92, 97};
std::cout << partial[2]; // Outputs: 0 (default initialized)

The size of a std::array is fixed at compile time. For dynamic resizing, use std::vector. Array indices start at 0, so a 3-element array has indices 0, 1, and 2.

2.2 — Array Manipulation
Expand →

Reading and Writing Elements

You can read and write individual array elements using bracket notation arr[index]. You can also read user input directly into an array element using std::cin.

C++ — Array layout & access
// Memory layout: [92][97][98][99][98][94]
// index: 0 1 2 3 4 5

std::array<int, 6> marks = {92, 97, 98, 99, 98, 94};

std::cout << marks[0]; // Read first element → 92
marks[1] = 99; // Write: change 2nd element to 99
std::cin >> marks[2]; // Read from user into 3rd element
2.3 — Displaying Arrays (Loops)
Expand →

Iterating Over Arrays

To print all elements, loop through the array. C++ offers two main styles: the range-based for loop (modern, cleaner) and the traditional index-based for loop (gives you the index).

C++
char ref[5] = {'R', 'e', 'f'};

// Method 1: Range-based for loop (C++11, recommended)
for (const int &n : ref) {
 std::cout << std::string(1, n); // Convert char to string and print
}

// Method 2: Traditional index-based for loop
for (int i = 0; i < sizeof(ref); ++i) {
 std::cout << ref[i]; // Access by index
}

Use const int &n in range-based loops to avoid copying large objects. The & means "reference" (no copy), and const means you won't modify it.

2.4 — Multidimensional Arrays
Expand →

2D Arrays — Arrays of Arrays

A 2D array is like a grid or table with rows and columns. You access elements using two indices: arr[row][col]. You need a nested loop (loop inside a loop) to traverse all elements.

C++ — 2×6 grid
// Grid layout:
// j→ 0 1 2 3 4 5
// i=0: 1 2 3 4 5 6
// i=1: 6 5 4 3 2 1

int x[2][6] = {
 {1, 2, 3, 4, 5, 6}, // Row 0
 {6, 5, 4, 3, 2, 1} // Row 1
};

for (int i = 0; i < 2; ++i) { // Loop over rows
 for (int j = 0; j < 6; ++j) { // Loop over columns
 std::cout << x[i][j] << " ";
 }
}
// Outputs: 1 2 3 4 5 6 6 5 4 3 2 1
03
Module 3 — Conditionals
if/else, operators, ternary, switch
0% · 0/4 done
3.1 — if / else if / else
Expand →

Conditional Branching

An if statement executes a block of code only when a condition is true. Add else to run code when it's false. Chain multiple conditions with else if. Only the first matching branch runs.

C++
// Basic if-else
int number = 16;
if (number % 2 == 0) {
 std::cout << "even"; // Runs when condition is true
} else {
 std::cout << "odd"; // Runs when all conditions above are false
}
// Outputs: even

// Chained else-if ladder
int score = 99;
if (score == 100) std::cout << "Superb";
else if (score >= 90) std::cout << "Excellent"; // ← This runs (99≥90)
else if (score >= 80) std::cout << "Very Good";
else if (score >= 70) std::cout << "Good";
else if (score >= 60) std::cout << "OK";
else std::cout << "What?";
3.2 — Operators (Relational, Assignment, Logical, Bitwise)
Expand →

C++ Operators

Operators are symbols that perform operations on values. C++ has four key categories: Relational (compare values), Assignment (modify and assign), Logical (combine boolean conditions), and Bitwise (work on individual bits).

1Relational (Comparison) Operators
a == ba equals b
a != ba is NOT equal to b
a < ba is less than b
a > ba is greater than b
a <= ba less than or equal
a >= ba greater or equal
2Assignment Operators
a += ba = a + b
a -= ba = a - b
a *= ba = a * b
a /= ba = a / b
a %= ba = a % b (remainder)
3Logical Operators
&& (AND)Both must be true
|| (OR)At least one true
! (NOT)Reverses truth value
4Bitwise Operators
a & bBinary AND
a | bBinary OR
a ^ bBinary XOR
~aOne's Complement
a << bShift left (×2ᵇ)
a >> bShift right (÷2ᵇ)
3.3 — Ternary Operator
Expand →

Compact if-else in One Line

The ternary operator condition ? valueIfTrue : valueIfFalse is a shorthand for a simple if-else that returns a value. It evaluates the condition and picks one of two expressions.

C++
// Ternary syntax: condition ? expr_if_true : expr_if_false
int x = 3, y = 5, max;

max = (x > y) ? x : y; // If x>y use x, else use y
std::cout << max; // Outputs: 5

// Equivalent if-else version (same result):
if (x > y) { max = x; }
else { max = y; }
std::cout << max; // Outputs: 5
3.4 — Switch Statement
Expand →

Multi-way Branching

A switch statement compares a variable against multiple exact values (cases). It's more readable than long if-else chains when testing a single variable against known constants. break stops execution from falling through to the next case. default runs if no case matches.

C++
int num = 2;
switch (num) {
 case 0:
 std::cout << "Zero";
 break; // MUST break to stop falling through!
 case 1:
 std::cout << "One";
 break;
 case 2:
 std::cout << "Two"; // ← This runs (num == 2)
 break;
 case 3:
 std::cout << "Three";
 break;
 default:
 std::cout << "What?"; // Runs if no case matched
 break;
}

Forgetting break causes fall-through — execution continues into the next case even if it doesn't match. This is sometimes intentional, but usually a bug.

04
Module 4 — Loops
while, do-while, for, range-based, break, continue, infinite
0% · 0/6 done
4.1 — while Loop
Expand →

Condition-First Loop

A while loop checks the condition before each iteration. If the condition is false from the start, the body never executes. Use when you don't know upfront how many times to loop.

C++
int i = 0;
while (i < 6) {
 std::cout << i++; // Print i, THEN increment (post-increment)
}
// Outputs: 012345
4.2 — do-while Loop
Expand →

Execute-First Loop

A do-while loop executes the body first, then checks the condition. The body always runs at least once, even if the condition is immediately false. Useful for menus and input validation.

C++
int i = 1;
do {
 std::cout << i++; // Runs FIRST, condition checked after
} while (i <= 5); // Note the semicolon here!
// Outputs: 12345
4.3 — for Loop & Variations
Expand →

Counter-Controlled Loop

The for loop packs init, condition, and increment into one line: for(init; condition; update). Perfect when you know exactly how many iterations you need. All three parts are optional.

C++
// Standard for loop
for (int i = 0; i < 10; i++) {
 std::cout << i << "\n";
}

// Multiple variables — i counts up, j counts down simultaneously
for (int i = 0, j = 2; i < 3; i++, j--) {
 std::cout << "i=" << i << ",j=" << j << ";";
}
// Outputs: i=0,j=2;i=1,j=1;i=2,j=0;
4.4 — Range-Based for & for_each (C++11)
Expand →

Modern Loop Syntax

The range-based for loop iterates over every element of a container without needing an index. It's cleaner and less error-prone. std::for_each applies a function to each element — pairs nicely with lambda expressions.

1Range-based for loopC++11
C++
// Loop over an initializer list directly
for (int n : {1, 2, 3, 4, 5}) {
 std::cout << n << " ";
}
// Outputs: 1 2 3 4 5

// Loop over a string character by character
std::string hello = "QuickRef.ME";
for (char c : hello) {
 std::cout << c << " ";
}
// Outputs: Q u i c k R e f . M E
2for_each with lambdaC++11
C++
#include <iostream>
#include <array>
#include <algorithm> // for std::for_each

int main() {
 // Lambda: [](params){ body } — anonymous inline function
 auto print = [](int num) { std::cout << num << std::endl; };

 std::array<int, 4> arr = {1, 2, 3, 4};
 std::for_each(arr.begin(), arr.end(), print);
 // Applies print() to each element: prints 1, 2, 3, 4
 return 0;
}
4.5 — break & continue
Expand →

Controlling Loop Flow

break immediately exits the entire loop. continue skips the rest of the current iteration and jumps to the next one. Both are valuable for flow control inside loops.

1continue — skip even numbers
C++
for (int i = 0; i < 10; i++) {
 if (i % 2 == 0) {
 continue; // Skip this iteration if i is even
 }
 std::cout << i; // Only odd numbers reach here
}
// Outputs: 13579
2break — lock out after 3 wrong passwords
C++
int password, times = 0;
while (password != 1234) {
 if (times++ >= 3) {
 std::cout << "Locked!\n";
 break; // Exit the while loop entirely
 }
 std::cout << "Password: ";
 std::cin >> password;
}
4.6 — Infinite Loops
Expand →

Loops That Never Stop

An infinite loop runs forever unless broken out of with break or return. They are intentional in server programs, game loops, and event listeners. Accidentally creating one is a common bug — make sure your loop condition eventually becomes false.

C++ — Three ways to write an infinite loop
// Method 1: while(true) — most readable
while (true) {
 std::cout << "infinite loop";
}

// Method 2: for(;;) — classic C style
for (;;) {
 std::cout << "infinite loop";
}

// Method 3: Condition that's always true (i++ always > 0)
for (int i = 1; i > 0; i++) {
 std::cout << "infinite loop";
}
05
Module 5 — Functions
Declaration, arguments, return, overloading, built-in functions
0% · 0/3 done
5.1 — Declaring, Defining & Calling Functions
Expand →

What is a Function?

A function is a named, reusable block of code. You declare it (tell the compiler it exists), define it (write what it does), and call it (execute it). Functions avoid code repetition and make programs modular and testable.

C++ — Full function lifecycle
#include <iostream>

void hello(); // DECLARATION (prototype) — tells compiler: hello exists
 // void = returns nothing, () = takes no arguments

int main() {
 hello(); // CALL — execute the function
 return 0;
}

void hello() { // DEFINITION — the actual code
 std::cout << "Hello QuickRef!\n";
}
2Function with arguments and return value
C++
// return_type function_name(param_type param, ...) { ... }
int add(int a, int b) { // Takes two ints, returns an int
 return a + b; // return sends value back to caller
}

int main() {
 std::cout << add(10, 20); // Prints: 30
}
5.2 — Function Overloading
Expand →

Same Name, Different Parameters

Function overloading allows multiple functions to have the same name as long as their parameter lists differ (different number or types of parameters). The compiler automatically picks the right version based on the arguments you pass.

C++
// Three versions of fun() — same name, different signatures
void fun(std::string a, std::string b) {
 std::cout << a + " " + b; // Called when 2 strings passed
}
void fun(std::string a) {
 std::cout << a; // Called when 1 string passed
}
void fun(int a) {
 std::cout << a; // Called when int passed
}

// Compiler picks correct version automatically:
fun("Hello", "World"); // → version 1 (2 strings)
fun("Hi"); // → version 2 (1 string)
fun(42); // → version 3 (int)
5.3 — Built-in Functions (cmath)
Expand →

Standard Library Functions

C++ ships with a rich standard library. The <cmath> header provides math functions like sqrt(), pow(), abs(), sin(), cos(), etc. Include the appropriate header and use the function — no need to implement it yourself.

C++
#include <iostream>
#include <cmath> // Import the math library

int main() {
 std::cout << std::sqrt(9); // √9 = 3
 std::cout << std::pow(2, 10); // 2¹⁰ = 1024
 std::cout << std::abs(-7); // |-7| = 7
 std::cout << std::floor(3.9); // ⌊3.9⌋ = 3
 std::cout << std::ceil(3.1); // ⌈3.1⌉ = 4
}
06
Module 6 — Classes & Objects
OOP fundamentals: classes, constructors, destructors, inheritance
0% · 0/7 done
6.1 — Defining a Class
Expand →

What is a Class?

A class is a blueprint for creating objects. It bundles data (attributes/member variables) and behavior (methods/member functions) together. Think of a class as the design, and an object as a real instance built from that design.

C++
class MyClass {
 public: // Access specifier: public = accessible from outside
 int myNum; // Attribute: integer variable
 std::string myString; // Attribute: string variable
}; // ← Don't forget the semicolon after the closing brace!

// Create an object (instance) of MyClass
MyClass myObj;

// Set attribute values using dot notation
myObj.myNum = 15;
myObj.myString = "Hello";

// Read attribute values
std::cout << myObj.myNum << std::endl; // 15
std::cout << myObj.myString << std::endl; // Hello
6.2 — Constructors
Expand →

Automatic Initialization

A constructor is a special method with the same name as the class and no return type. It automatically runs when an object is created. Use it to set default values and initialize resources.

C++
class MyClass {
 public:
 int myNum;
 std::string myString;

 MyClass() { // Constructor — same name as class, no return type
 myNum = 0; // Initialize to defaults
 myString = "";
 }
};

MyClass myObj; // Constructor runs automatically here
std::cout << myObj.myNum; // 0 (set by constructor)
std::cout << myObj.myString; // "" (set by constructor)
6.3 — Destructors
Expand →

Automatic Cleanup

A destructor is called automatically when an object goes out of scope or is deleted. Its name is the class name prefixed with ~. Use it to free resources (memory, file handles, network connections) the object acquired during its lifetime.

C++
class MyClass {
 public:
 int myNum; std::string myString;

 MyClass() { myNum = 0; myString = ""; } // Constructor

 ~MyClass() { // Destructor (note ~)
 std::cout << "Object destroyed." << std::endl;
 }
};

MyClass myObj; // Constructor called here
// ... use myObj ...
// Destructor called automatically when myObj goes out of scope
6.4 — Class Methods
Expand →

Functions Inside a Class

Methods (member functions) are functions defined inside a class that can access the class's attributes. Call them with dot notation: obj.method().

C++
class MyClass {
 public:
 int myNum;
 std::string myString;

 void myMethod() { // Method defined inside the class
 std::cout << "Hello World!" << std::endl;
 }
};

MyClass myObj;
myObj.myMethod(); // Call the method → prints: Hello World!
6.5 — Access Modifiers (public / private / protected)
Expand →

Controlling Access to Class Members

Access modifiers control who can read or write class members. public: anyone can access. private: only the class itself. protected: the class and its derived (child) classes. This is the foundation of encapsulation — hiding internal details.

C++
class MyClass {
 public:
 int x; // Accessible from anywhere
 private:
 int y; // Only accessible within this class
 protected:
 int z; // Accessible within this class and subclasses
};

MyClass myObj;
myObj.x = 25; // OK — public
myObj.y = 50; // ERROR — private, not accessible outside
myObj.z = 75; // ERROR — protected, not accessible outside
6.6 — Getters & Setters
Expand →

Controlled Access to Private Data

Getters and setters are public methods that provide controlled access to private attributes. Setters can validate input before setting. Getters return the value without exposing the raw variable.

C++
class MyClass {
 private:
 int myNum; // Private: can't access directly

 public:
 void setMyNum(int num) { // Setter: validates then stores
 myNum = num;
 }
 int getMyNum() { // Getter: returns private value
 return myNum;
 }
};

MyClass myObj;
myObj.setMyNum(15); // Set via setter (indirect write)
std::cout << myObj.getMyNum(); // Get via getter → 15
6.7 — Inheritance
Expand →

Reusing Code via Inheritance

Inheritance lets a derived class (child) inherit attributes and methods from a base class (parent). Use class Derived : public Base. The child gets all public and protected members of the parent, and can add its own.

C++
class Vehicle { // BASE class (parent)
 public:
 std::string brand = "Ford";
 void honk() {
 std::cout << "Tuut, tuut!" << std::endl;
 }
};

class Car : public Vehicle { // DERIVED class (child) — inherits Vehicle
 public:
 std::string model = "Mustang"; // Car's own attribute
};

Car myCar;
myCar.honk(); // Inherited from Vehicle → "Tuut, tuut!"
std::cout << myCar.brand + " " + myCar.model; // Ford Mustang
07
Module 7 — Preprocessor
Directives: include, define, ifdef, macros, error, pragma
0% · 0/6 done
7.1 — #include
Expand →

Including Headers

The #include directive tells the preprocessor to paste the contents of another file into your source file before compilation. Angle brackets <> are used for standard library headers; quotes "" are used for your own local headers.

C++
#include <iostream> // Standard library header (system path)
#include "myfile.h" // Your own header (current directory first)
7.2 — #define & #undef
Expand →

Preprocessor Constants & Macros

#define creates a macro — the preprocessor does a text substitution everywhere the macro name appears. #undef removes a previously defined macro. Unlike const, defines have no type checking.

C++
#defineFOO // Define FOO as a flag (no value)
#defineFOO "hello" // Define FOO as the text "hello"
#undefFOO // Remove the FOO macro
7.3 — Conditional Compilation (#ifdef / #if / #endif)
Expand →

Compile Different Code Conditionally

Preprocessor conditionals let you include or exclude blocks of code at compile time — before the compiler even sees them. Commonly used for debug-only code, platform-specific code, and feature flags.

C++
// #ifdef: "if DEBUG macro is defined"
#ifdefDEBUG
 console.log('hi'); // Only compiled in debug build
#elif definedVERBOSE
 // ... compiled if VERBOSE defined but not DEBUG
#else
 // ... compiled if neither DEBUG nor VERBOSE
#endif // Always end with #endif
7.4 — #error & #warning
Expand →

Compile-Time Messages

#error halts compilation and displays a message — useful for catching unsupported configurations. #warning shows a warning but continues compiling. These run before your code ever executes.

C++
#ifVERSION == 2.0
 #errorUnsupported // STOPS compilation with this error message
 #warningNot really supported // Shows warning but continues
#endif
7.5 — Macros: Token Concat & Stringification
Expand →

Advanced Macro Tricks

Macros can take parameters like functions. The ## operator concatenates tokens (joins two identifiers together). The # operator stringifies — converts a token into a string literal. Both happen at compile time.

C++
// Parameterized macro: like a function but text-substituted
#define DEG(x) ((x) * 57.29) // Converts radians to degrees

// Token concatenation with ##
#define DST(name) name##_s name##_t
DST(object); // Expands to: object_s object_t;

// Stringification with # — wraps in double quotes
#define STR(name) #name
char * a = STR(object); // Expands to: char * a = "object";

// __FILE__ and __LINE__ — built-in macros
#define LOG(msg) console.log(__FILE__, __LINE__, msg)
// Expands to: console.log("file.txt", 3, "hey")
7.6 — All Preprocessor Directives (Reference)
Expand →

Complete Directive Reference

Here is every preprocessor directive available in standard C++. All of them start with # and are processed before compilation begins.

DirectivePurpose
#ifConditional if expression is true
#elifElse-if for preprocessor conditionals
#elseElse branch for preprocessor
#endifEnds an #if / #ifdef / #ifndef block
#ifdefIf macro IS defined
#ifndefIf macro is NOT defined (include guards)
#defineDefine a macro or constant
#undefUndefine (remove) a macro
#includeInclude a header file
#lineSet line number for error reporting
#errorEmit error and stop compilation
#pragmaCompiler-specific directives (e.g., once)
#definedOperator: check if macro is defined
export / import / moduleC++20 module system