Functions

Functions package a piece of logic under a name so you can reuse it, test it and reason about it on its own. C++ functions have typed parameters and return values, can be declared before they're defined, and can return several values at once with structured bindings.

Defining and calling

C++
#include <iostream>

double rectangle_area(double width, double height) {
    return width * height;
}

void print_divider() {
    std::cout << "----------\n";
}

int main() {
    print_divider();
    std::cout << "Kitchen: " << rectangle_area(4.2, 3.0) << " m2\n";
    std::cout << "Hall:    " << rectangle_area(6.0, 1.2) << " m2\n";
    print_divider();
}
Output
----------
Kitchen: 12.6 m2
Hall:    7.2 m2
----------

A function has a return type (void for none), a name, a parameter list and a body. return sends a value back and ends the function.

Declarations

A function must be declared before it's called. A declaration (or prototype) gives the signature without the body; the definition can come later — or in another file (lesson 48):

C++
#include <iostream>

bool is_prime(int n);      // declaration

int main() {
    for (int n = 1; n <= 20; ++n) {
        if (is_prime(n)) std::cout << n << ' ';
    }
    std::cout << '\n';
}

bool is_prime(int n) {     // definition
    if (n < 2) return false;
    for (int d = 2; d * d <= n; ++d) {
        if (n % d == 0) return false;
    }
    return true;
}
Output
2 3 5 7 11 13 17 19

In C++, empty parentheses mean "no parameters" — no void needed.

Return type deduction

auto as a return type lets the compiler deduce it from the return statements. A trailing return type (-> type) is another way to write the type, common with templates and lambdas:

C++
#include <iostream>

auto average(int a, int b) {        // deduced: double
    return (a + b) / 2.0;
}

auto square(int x) -> long long {   // trailing return type
    return 1LL * x * x;
}

int main() {
    std::cout << average(3, 4) << ' ' << square(100000) << '\n';
}
Output
3.5 10000000000

Returning several values

Return a struct (or std::pair/std::tuple) and unpack it with a structured binding:

C++
#include <iostream>
#include <vector>

struct MinMax {
    int min;
    int max;
};

MinMax min_max(const std::vector<int>& values) {
    MinMax r{values.front(), values.front()};
    for (int v : values) {
        if (v < r.min) r.min = v;
        if (v > r.max) r.max = v;
    }
    return r;
}

int main() {
    std::vector<int> temps{14, 9, 21, 17, 6};
    auto [lo, hi] = min_max(temps);
    std::cout << "min " << lo << ", max " << hi << '\n';
}
Output
min 6, max 21

This is clearer than C-style output parameters. Lesson 14 explains the const std::vector<int>& parameter.

[[nodiscard]]

Mark a function whose result must not be ignored — for example one that reports success or failure. The compiler warns if a caller throws the result away:

C++
#include <string>

[[nodiscard]] bool save(const std::string& filename) {
    return !filename.empty();
}

int main() {
    save("notes.txt");    // result ignored
}
Compiler warnings
main.cpp:8:5: warning: ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]

Recursion

A function can call itself, as long as it has a base case that stops the recursion:

C++
#include <iostream>

unsigned long long factorial(unsigned n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

int main() {
    std::cout << factorial(20) << ' ' << gcd(1071, 462) << '\n';
}
Output
2432902008176640000 21

Each call uses stack space, so for very deep repetition a loop is safer. Recursion suits naturally nested problems such as trees and divide-and-conquer algorithms.

Good functions

  • Do one thing, and name it after what it does: parse_date, is_valid, print_report.
  • Keep them short enough to read at a glance.
  • Take inputs as parameters and give results as return values, rather than relying on global variables.
  • Prefer returning a struct over several output parameters.

Try it yourself

Write count_vowels and use it on a few words.

Try it yourself · main.cpp
Edit the code, copy it into main.cpp, then compile and run it with c++ -std=c++20 -Wall main.cpp -o main && ./main. How to set up a C++ compiler
Output
Programming: 3
rhythm: 0
Education: 5