Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Day 21: Lambda Expressions and Functional Programming in C++ #323

Merged
merged 7 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions docs/day-21/Lambda Expressions and Functional Programming copy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
---
sidebar_position: 1
title: "Lambda Expressions in C++"
description: "In this tutorial, we will learn about lambda expressions in C++ with the help of examples. Lambda expressions provide a way to create anonymous functions, useful for functional programming in C++."
sidebar_label: "Lambda Expressions"
slug: lambda-expressions-in-cpp
---

## Introduction:

Lambda expressions provide a way to create anonymous functions (i.e., functions without a name) in C++. They are particularly useful for short snippets of code that are passed to algorithms or used as callbacks. Functional programming, which emphasizes immutability and first-class functions, can be effectively implemented in C++ using lambda expressions and the standard library's functional utilities.

![30-days-of-cpp-introduction](../../static/img/day-21/Lambda%20Function.jpg)

#### 1. Lambda Expressions:

A lambda expression in C++ allows you to define an inline function directly in the code where it is used. This is especially useful for short operations, such as those passed to algorithms.


#### 2. Syntax of Lambda Expressions:

The basic syntax of a lambda expression is:
```cpp
[capture](parameters) -> return_type { body }
```

- **Capture**: Specifies which variables are captured from the surrounding scope.
- **Parameters**: The parameters passed to the lambda, similar to a regular function.
- **Return type**: (Optional) The return type of the lambda. It can often be inferred by the compiler.
- **Body**: The code that gets executed when the lambda is called.

Example:
```cpp
auto add = [](int a, int b) -> int {
return a + b;
};
std::cout << "Sum: " << add(2, 3) << std::endl; // Output: Sum: 5
```

#### 3. Capturing Variables:

Lambda expressions can capture variables from their enclosing scope. There are several ways to capture variables:
- **Capture by value**: `[x, y]` captures `x` and `y` by value.
- **Capture by reference**: `[&x, &y]` captures `x` and `y` by reference.
- **Capture all by value**: `[=]` captures all variables by value.
- **Capture all by reference**: `[&]` captures all variables by reference.
- **Mixed capture**: `[=, &x]` captures all variables by value except `x`, which is captured by reference.

Example:
```cpp
int x = 10;
int y = 20;

auto printSum = [x, y]() {
std::cout << "Sum: " << x + y << std::endl;
};

printSum(); // Output: Sum: 30
```

#### 4. Using Lambdas with Standard Algorithms:

Lambdas are particularly useful with the Standard Template Library (STL) algorithms. Here’s an example using `std::for_each`:

```cpp
#include <algorithm>
#include <vector>
#include <iostream>

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::for_each(numbers.begin(), numbers.end(), [](int n) {
std::cout << n << " ";
});
// Output: 1 2 3 4 5
return 0;
}
```

#### 5. Lambdas as Callbacks:

Lambdas can be used as callbacks for event handling or asynchronous operations. Here’s an example with a simple callback mechanism:

```cpp
#include <iostream>
#include <functional>

void performOperation(const std::function<void(int)>& callback) {
int result = 42; // Imagine this is the result of some operation
callback(result);
}

int main() {
performOperation([](int result) {
std::cout << "Operation result: " << result << std::endl;
});
// Output: Operation result: 42
return 0;
}
```

#### 6. Practical Examples and Exercises:

**Example 1: Sorting a Vector with a Lambda**

```cpp
#include <algorithm>
#include <vector>
#include <iostream>

int main() {
std::vector<int> numbers = {5, 2, 9, 1, 5, 6};

std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a < b;
});

for (int n : numbers) {
std::cout << n << " ";
}
// Output: 1 2 5 5 6 9
return 0;
}
```

**Example 2: Filtering Elements with `std::copy_if` and a Lambda**

```cpp
#include <algorithm>
#include <vector>
#include <iostream>

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::vector<int> evenNumbers;

std::copy_if(numbers.begin(), numbers.end(), std::back_inserter(evenNumbers), [](int n) {
return n % 2 == 0;
});

for (int n : evenNumbers) {
std::cout << n << " ";
}
// Output: 2 4 6 8 10
return 0;
}
```

**Exercises:**

1. Write a lambda function to calculate the factorial of a number.
2. Use a lambda to transform a vector of integers by squaring each element.
3. Create a lambda that captures a local variable by reference and modifies it within the lambda.


132 changes: 132 additions & 0 deletions docs/day-21/Macros.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
sidebar_position: 2
title: "Macros in C++"
description: "Learn about macros in C++, their usage, and best practices with practical examples. Macros are powerful preprocessor directives that enable code substitution before compilation."
sidebar_label: "Macros in C++"
slug: macros-in-cpp
---

## Introduction:

Macros in C++ are preprocessor directives that allow for code substitution before compilation. They are used to define constants, create inline functions, and conditionally include code segments.

![macros-in-cpp-introduction](../../static/img/day-21/Macros%20in%20cpp.jpg)

#### 1. Defining Constants with `#define`:

Macros are commonly used to define constants that are substituted directly into the code.

```cpp
#define PI 3.14159

#include <iostream>

int main() {
std::cout << "Value of PI: " << PI << std::endl;
return 0;
}
```

#### 2. Function-like Macros:

You can create macros that act like functions, allowing for parameterized code substitution.

```cpp
#define SQUARE(x) ((x) * (x))

#include <iostream>

int main() {
int num = 5;
std::cout << "Square of " << num << " is: " << SQUARE(num) << std::endl;
return 0;
}
```

#### 3. Conditional Compilation:

Macros enable conditional compilation, where certain code segments are included or excluded based on defined conditions.

```cpp
#define DEBUG_MODE

#include <iostream>

int main() {
#ifdef DEBUG_MODE
std::cout << "Debug mode is on" << std::endl;
#endif
std::cout << "Program running" << std::endl;
return 0;
}
```

#### 4. Include Guards:

Include guards prevent multiple inclusions of the same header file, ensuring the contents are only included once per translation unit.

```cpp
#ifndef MY_HEADER_H
#define MY_HEADER_H

// Header file content

#endif // MY_HEADER_H
```

#### 5. Best Practices and Considerations:

- **Use sparingly**: Overuse of macros can lead to code maintenance issues.
- **Prefer `const` or `constexpr`**: Use `const` variables or `constexpr` for constants instead of macros where possible.
- **Parenthesize**: Always parenthesize macro arguments and the entire expression to avoid unintended side effects.

#### 6. Practical Examples and Exercises:

**Example 1: Sorting with a Macro**

```cpp
#include <algorithm>
#include <vector>
#include <iostream>

#define SORT_DESCENDING(vec) std::sort(vec.begin(), vec.end(), [](int a, int b) { return a > b; })

int main() {
std::vector<int> numbers = {5, 2, 9, 1, 5, 6};

SORT_DESCENDING(numbers);

for (int n : numbers) {
std::cout << n << " ";
}
// Output: 9 6 5 5 2 1
return 0;
}
```

**Example 2: Conditional Compilation**

```cpp
#include <iostream>

#define DEBUG_MODE

int main() {
#ifdef DEBUG_MODE
std::cout << "Debug mode is on" << std::endl;
#else
std::cout << "Debug mode is off" << std::endl;
#endif

std::cout << "Program running" << std::endl;
return 0;
}
```

**Exercises:**

1. Define a macro to calculate the factorial of a number.
2. Implement a macro for checking if a number is even.
3. Create a macro that swaps two variables.


7 changes: 7 additions & 0 deletions docs/day-21/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"label": "Day 21",
"position": 21,
"link": {
"type": "generated-index"
}
}
Binary file added static/img/day-21/Lambda Function.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/img/day-21/Macros in cpp.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.