{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Function Declarations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### final and override"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The modifier `virtual` indicates that a method can be overridden by a child class.\n",
    "\n",
    "The `override` modifier indicates to the compiler that a child class intends to override a parent's virtual function.\n",
    "\n",
    "The `final` modifier indicates that a method cannot be overridden by a child class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "input_line_7:8:10: error: declaration of 'go' overrides a 'final' function\n",
      "    void go() override {}; // An error will arise\n",
      "         ^\n",
      "input_line_7:2:18: note: overridden virtual function is here\n",
      "    virtual void go() final {\n",
      "                 ^\n"
     ]
    },
    {
     "ename": "Interpreter Error",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "Interpreter Error: "
     ]
    }
   ],
   "source": [
    "struct Boat {\n",
    "    virtual void go() final {\n",
    "        printf(\"'virtual' indicates that you can override this function on child class, but since you use 'final' at the end, error will raise\");\n",
    "    }\n",
    "};\n",
    "\n",
    "struct SkyBoat: Boat {\n",
    "    void go() override {}; // An error will arise\n",
    "};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### auto and decltype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "template <typename X, typename Y>\n",
    "auto add(X x, Y y) -> decltype(x+y) {\n",
    "    return x + y;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "110.00000"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "add(100.0, 10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "110"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "add(100u, 10) //unsigned int"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "110"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "add(100ull, 10) //unsigned long long"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`decltype` seems useless in here."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Variadic Functions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Similar to python's * inside a function arguments."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <cstdio>\n",
    "#include <cstdint>\n",
    "#include <cstdarg>\n",
    "\n",
    "int sum(size_t n, ...) {\n",
    "    va_list args;\n",
    "    va_start(args, n);\n",
    "    int result{};\n",
    "    while (n--) {\n",
    "        auto next_element = va_arg(args, int);\n",
    "        result += next_element;\n",
    "    }\n",
    "    va_end(args);\n",
    "    return result;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "13"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum(3,10,1,2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You declare `sum` as a variadic function. \n",
    "\n",
    "All variadic functions must declare a `va_list`. You’ve named it `args`. \n",
    "\n",
    "A `va_list` requires initialization with `va_start`, which takes two arguments. The first argument is a `va_list`, and the second is the size of the variadic arguments. \n",
    "\n",
    "You iterate over each element in the variadic arguments using the `va_args` function. The first argument is the `va_list` argument, and the second is the `argument type x`.\n",
    "\n",
    "Once you’ve completed iterating, you call `va_end`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Variadic Templates"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <cstdio>\n",
    "\n",
    "template <typename T>\n",
    "constexpr T sum(T x) {\n",
    "    return x;\n",
    "}\n",
    "\n",
    "template <typename T, typename... Args>\n",
    "constexpr T sum(T x, Args... args) {\n",
    "    return x + sum(args...);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3996"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum(1998, 1998)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Fold Expressions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "template <typename... T>\n",
    "constexpr auto minus(T... args) {\n",
    "    return (... - args);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "minus(3,2,1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(... binary-operator parameter-pack)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Function Pointers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "int add(int a, int b) {\n",
    "    return a + b;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "int subtract(int a, int b) {\n",
    "    return a - b;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "const int a{100};\n",
    "const int b{50};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "operation initialized to 0x(nil)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "33"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int (*a_function_pointer)(int, int) {};\n",
    "//or\n",
    "//using a_function_pointer = int(*)(int, int);\n",
    "printf(\"operation initialized to 0x%p\\n\", a_function_pointer); // this is probably a memory address"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0x0x7f6b0ab8a120\n",
      "\n",
      "a+b=150\n"
     ]
    }
   ],
   "source": [
    "// auto a_function_pointer = whatever\n",
    "a_function_pointer = &add;\n",
    "printf(\"0x%p\\n\\n\", a_function_pointer);\n",
    "printf(\"a+b=%d\\n\", a_function_pointer(a, b));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0x0x7f6b0a631120\n",
      "\n",
      "a-b=50\n"
     ]
    }
   ],
   "source": [
    "a_function_pointer = &subtract;\n",
    "printf(\"0x%p\\n\\n\", a_function_pointer);\n",
    "printf(\"a-b=%d\\n\", a_function_pointer(a, b));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The Function-Call Operator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <cstdio>\n",
    "#include <cstdint>\n",
    "\n",
    "struct CountIf {\n",
    "    CountIf(char x) : x{ x } {}\n",
    "    size_t operator()(const char* str) const {\n",
    "        size_t index{}, result{};\n",
    "        while (str[index]) { // iterate the string until the end of that string\n",
    "            if (str[index] == x) {\n",
    "                result++;\n",
    "            }\n",
    "            index++;\n",
    "        }\n",
    "        return result;\n",
    "    }\n",
    "private:\n",
    "    const char x;\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "CountIf s_counter( 's' );\n",
    "s_counter(\"s will be count once.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So what this operator does is to let you use the class as a function"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lambda Expressions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9"
     ]
    }
   ],
   "source": [
    "auto func = [](int x) constexpr -> int { return x*x; };\n",
    "printf(\"%d\", func(3));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <cstdint>\n",
    "\n",
    "template <typename Fn>\n",
    "void run(Fn fn, int& num) {\n",
    "    num = fn(num);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int a = 2;\n",
    "run(func, a);\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lambda Captures"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9"
     ]
    }
   ],
   "source": [
    "int a = 3;\n",
    "\n",
    "auto do_it_by_using_reference = [&]() -> void { a = a * a; };\n",
    "//auto do_it_by_using_value = [=](int x) -> int { return x*x; };\n",
    "\n",
    "do_it_by_using_reference();\n",
    "printf(\"%d\", a);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## std::function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <cstdio>\n",
    "#include <functional>\n",
    "\n",
    "/*\n",
    "std::function<void()> func {[] { printf(\"this is from a lambda function\"); }};\n",
    "func();\n",
    "*/\n",
    "// this should work in a normal cpp program"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The main Function and the Command Line"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <cstdio>\n",
    "#include <cstdint>\n",
    "\n",
    "int main(int argc, char** argv) {\n",
    "    printf(\"Arguments: %d\\n\", argc);\n",
    "    for (size_t i{}; i < argc; i++) {\n",
    "        printf(\"%zd: %s\\n\", i, argv[i]);\n",
    "    }\n",
    "    return 0;\n",
    "}\n",
    "\n",
    "// this will print out the string arguments you gave when you run your program as a command line"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "codemirror_mode": "text/x-c++src",
   "file_extension": ".cpp",
   "mimetype": "text/x-c++src",
   "name": "c++",
   "version": "17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
