# Callback keyword and Pass a function as an argument in C++

We will walk  through the concepts of **callbacks** and **passing functions as arguments** in C++.

#### 1. What is a "Callback"?

A **callback** is a function that you pass as an argument to another function, and that function can call (or "invoke") the passed-in function at some point. It's like saying, "I'll pass you this function, and you call it when you need it."

In C++, callbacks are usually implemented using function pointers or, more commonly in modern C++, using **`std::function`** and **lambdas** (anonymous functions).

#### 2. How to Pass a Function as an Argument in C++?

In C++, you can pass functions as arguments using the following techniques:

* **Function Pointers** (classic C++ approach)
* **`std::function`** (modern C++ approach, introduced in C++11)
* **Lambdas** (anonymous inline functions, introduced in C++11)

**Example of Using Function Pointers:**

If you have a function `myFunction` that you want to pass to another function, you can use function pointers.

```cpp
// Define a function
void myFunction(int x) {
    std::cout << "Called with: " << x << std::endl;
}

// Function that takes a function pointer as an argument
void callWithArgument(void (*callback)(int), int value) {
    // Call the function passed as the callback
    callback(value);
}

int main() {
    // Pass myFunction as a function pointer
    callWithArgument(myFunction, 42);
}
```

Output:

```
Called with: 42
```

**Example of Using `std::function` and Lambdas:**

In modern C++, **`std::function`** is used to pass functions as arguments, and **lambdas** are inline anonymous functions that can be passed to `std::function`.

Here’s an example using both:

```cpp
#include <iostream>
#include <functional> // For std::function

// A function that takes a std::function (callback) as an argument
void callWithCallback(std::function<void(int)> callback, int value) {
    // Call the function passed as the callback
    callback(value);
}

int main() {
    // Lambda function that can be passed as a callback
    auto lambda = [](int x) {
        std::cout << "Lambda called with: " << x << std::endl;
    };

    // Call with lambda as the callback
    callWithCallback(lambda, 42);

    // You can also pass a regular function
    callWithCallback([](int x) { std::cout << "Inline Lambda called with: " << x << std::endl; }, 10);
}
```

Output:

```
Lambda called with: 42
Inline Lambda called with: 10
```

#### 3. How to Use a Function as an Argument in C++?

When you want to pass a function as an argument, the function you pass could either be:

* A regular function
* A lambda function
* A function pointer
* A `std::function` type, which can hold a variety of callable objects (including lambdas, function pointers, and more)

In KVDB project, we use **`std::function<void(const KeyValue&)>`** in the `inOrderTraversal` function, passing a function (or lambda) that takes a `KeyValue` and returns `void`.

Here's an example using `std::function` in a tree traversal:

#### Using `std::function` in Tree Traversal

```cpp
#include <functional>  // For std::function
#include <iostream>

// Simplified KeyValue structure
struct KeyValue {
    int key;
    int value;
    
    KeyValue(int k, int v) : key(k), value(v) {}
    
    bool operator>=(const KeyValue& other) const { return key >= other.key; }
    bool operator<=(const KeyValue& other) const { return key <= other.key; }
    ...
    ...
};

// Simplified RedBlackTree class with an inOrderTraversal method
class RedBlackTree {
public:
    struct TreeNode {
        KeyValue keyValue;
        TreeNode* left;
        TreeNode* right;

        TreeNode(KeyValue kv) : keyValue(kv), left(nullptr), right(nullptr) {}
    };

    RedBlackTree() : root(nullptr) {}

    // Insert for demonstration (simplified, non-balanced insertion)
    void insert(KeyValue kv) {
        root = insertRec(root, kv);
    }

    // Inorder traversal with callback (using std::function)
    void inOrderTraversal(std::function<void(const KeyValue&)> callback) const {
        inOrderTraversal(root, callback);
    }

private:
    TreeNode* root;

    TreeNode* insertRec(TreeNode* node, KeyValue kv) {
        if (!node) return new TreeNode(kv);
        if (kv.key < node->keyValue.key) node->left = insertRec(node->left, kv);
        else node->right = insertRec(node->right, kv);
        return node;
    }

    void inOrderTraversal(TreeNode* node, std::function<void(const KeyValue&)> callback) const {
        if (node == nullptr) return;
        inOrderTraversal(node->left, callback);  // Visit left subtree
        callback(node->keyValue);                // Apply callback to current node
        inOrderTraversal(node->right, callback); // Visit right subtree
    }
};

int main() {
    RedBlackTree tree;
    tree.insert(KeyValue(10, 100));
    tree.insert(KeyValue(5, 50));
    tree.insert(KeyValue(20, 200));

    // Use inOrderTraversal with a lambda callback
    tree.inOrderTraversal([](const KeyValue& kv) {
        std::cout << "Key: " << kv.key << ", Value: " << kv.value << std::endl;
    });

    return 0;
}
```

#### Output:

```
Key: 5, Value: 50
Key: 10, Value: 100
Key: 20, Value: 200
```

#### Explanation:

1. **Lambda Functions**: The `inOrderTraversal` function accepts a lambda as a callback. This lambda processes each key-value pair during the traversal.
2. **`std::function`**: `std::function<void(const KeyValue&)>` is used to define the type of the callback function, which takes a `KeyValue` as an argument and returns `void`.

#### Summary:

* **Callback** refers to a function passed as an argument to another function, which is called ("invoked") within the receiving function.
* You can pass functions as arguments using **function pointers** or **`std::function`** (the modern approach).
* **Lambdas** are a convenient way to define inline, anonymous functions and pass them as arguments.
