Language[lang]
C++ functions: syntax, calling and overloading
- Section
- Language [lang]
- Standard
- C++17
- Compilers
- MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2, Clang 23.1 (libc++)
- Published
- Length
- 7 min read
Abstract
C++ functions are named blocks of code you write once and call by name: int add(int a, int b) { return a + b; } has a return type, a name, parameters and a body, and add(2, 3) gives back 5. A function must be declared above the line that calls it, either defined there or declared with a prototype. Parameters are copies unless they are references, default arguments fill in what a call leaves out, and overloads share one name with different parameter lists.

C++ functions are named blocks of code that you write once and call wherever you need them. int add(int a, int b) { return a + b; } has a return type, a name, parameters and a body; add(2, 3) calls it and gives back 5. A function must be declared before the line that calls it.
That function in a whole program, called twice:
#include <iostream>
int add(int a, int b) {
return a + b;
}
int main() {
std::cout << add(2, 3) << '\n'; // 5
std::cout << add(10, 32) << '\n'; // 42
}— end example]
It printed 5, then 42. The samples are C++17, built with MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2 and Clang 23.1 (libc++), and every program printed the same on all four. Since When lists the first compiler releases for each standard.
What are the parts of a C++ function?
A function has a return type (int), a name (add), parameters in parentheses (int a, int b) and a body in braces, where return hands a value back to the caller. The drawing labels each part and traces a call:

A parameter is a name in the function’s own list, here a and b. An argument is what a call passes for it: in add(2, 3), a starts as 2 and b as 3, the body runs, and the call gives back 5.
What is a void function?
A void function returns nothing: it does a job, such as printing, and its call is a statement on its own. Inside it, return; with no value leaves early:
void greet(const std::string& name) {
std::cout << "Hello, " << name << '\n';
}
void print_if_positive(int n) {
if (n <= 0) {
return; // leaves now: there is no value to hand back
}
std::cout << n << '\n';
}
// ...
greet("Ada"); // Hello, Ada
print_if_positive(7); // 7
print_if_positive(-2); // prints nothing— end example]
It printed Hello, Ada and 7; the call with -2 printed nothing. The const std::string& in greet is explained under pass by value or by reference, below.
Every function that is not void must return a value on every path. This sign forgets the case where n is 0:
int sign(int n) {
if (n > 0) {
return 1;
}
if (n < 0) {
return -1;
}
// n == 0 reaches the closing brace: no value is returned
}— end example]
With warnings on (-Wall -Wextra for GCC and Clang, /W4 for MSVC), all four built it and warned; none refused. GCC said control reaches end of non-void function. Reaching that brace is undefined behavior, meaning the standard sets no rule for what the program does ([stmt.return]), so treat the warning as an error and add return 0;. main is exempt: reaching its closing brace returns 0, which is why the first program needs no return.
Why must a function be declared before it is called?
Because, outside a class, a name can be used only after its declaration: the compiler reads the file from the top, and a call to a name it has not met yet is an error (name lookup on cppreference). Define add below main, and the call fails:
int main() {
int sum = add(2, 3); // error: add is not declared yet
std::cout << sum << '\n';
}
int add(int a, int b) {
return a + b;
}— end example]
GCC said 'add' was not declared in this scope, and the other three refused it in their own words.
There are two fixes: define the function above main, as the first program does, or put a declaration above main and the definition below. A declaration, also called a prototype, is the function’s first line with a semicolon in place of the body:
#include <iostream>
int add(int a, int b); // declaration (prototype): first line and ;
int main() {
int sum = add(2, 3);
std::cout << sum << '\n'; // 5
}
int add(int a, int b) { // definition: the body comes later
return a + b;
}— end example]
It printed 5. In a program of several files, the declarations live in a header file.
Pass by value or by reference?
By default a parameter is a copy of its argument, so changing it changes nothing outside the function. A parameter written int&, a reference, is another name for the caller’s own variable:
void add_one_copy(int n) {
n = n + 1; // changes the copy only
}
void add_one(int& n) {
n = n + 1; // changes the caller's variable
}
std::size_t length(const std::string& text) {
return text.size(); // reads the caller's string, no copy
}
// ...
int count = 5;
std::cout << count << '\n'; // 5
add_one_copy(count);
std::cout << count << '\n'; // still 5
add_one(count);
std::cout << count << '\n'; // 6
std::string word = "functions";
std::cout << length(word) << '\n'; // 9— end example]
It printed 5, 5, 6 and 9. length shows the third form, the one greet uses: a const std::string& parameter refers to the caller’s string instead of copying it, and const keeps the function from changing it. Which form to pick for which type is in pass by value or const reference.
What are default arguments in C++?
A default argument is a value written in the parameter list, int times = 1, that the function gets when a call leaves that argument out:
void greet(const std::string& name, int times = 1) {
for (int i = 0; i < times; ++i) {
std::cout << "Hello, " << name << '\n';
}
}
// ...
greet("Ada"); // times is 1: one line
greet("Grace", 3); // times is 3: three lines— end example]
It printed Hello, Ada once and Hello, Grace three times. Defaults go on the last parameters: once one parameter has a default, every parameter after it needs one too (default arguments on cppreference). With a prototype, write the default there and not again in the definition: the standard forbids repeating it, even with the same value ([dcl.fct.default]).
What is function overloading in C++?
Function overloading is several functions with one name and different parameter lists; the compiler picks the one whose parameters match the arguments best:
double area(double side) {
return side * side;
}
double area(double width, double height) {
return width * height;
}
void print(int n) {
std::cout << "int: " << n << '\n';
}
void print(const std::string& text) {
std::cout << "string: " << text << '\n';
}
// ...
std::cout << area(3.0) << '\n'; // one argument: 9
std::cout << area(2.0, 3.5) << '\n'; // two arguments: 7
print(42); // int: 42
print("forty-two"); // string: forty-two— end example]
It printed 9, 7, int: 42 and string: forty-two. The matching step is overload resolution, and because the compiler does it while it builds the program, overloading is compile-time polymorphism.
A different return type alone is not enough:
int parse(const std::string& text) {
return std::stoi(text);
}
double parse(const std::string& text) { // error: only the return
return std::stod(text); // type differs
}— end example]
All four refused it. Clang’s message states the rule: functions that differ only in their return type cannot be overloaded.
Common C++ function errors
| GCC says | Cause | Fix |
|---|---|---|
'add' was not declared in this scope |
the call comes before any declaration of add |
define add above the call, or declare it there |
too few arguments to function 'int add(int, int)' |
add(2) passes one argument for two parameters |
pass one per parameter, or give the last a default |
control reaches end of non-void function (a warning) |
a path through the body has no return |
return a value on every path |
redefinition of 'double area(double, double)' |
the same function defined twice | keep one, or change its parameters to overload it |
Clang and MSVC word these differently: for a call before the declaration, Clang says use of undeclared identifier 'add'. The Language section has more answers on the core language.
Questions
What is the difference between a parameter and an argument?
A parameter is a name in the function’s own list, such as a and b in int add(int a, int b). An argument is what a call passes for it: in add(2, 3), the arguments are 2 and 3. When the call starts, each argument initializes its parameter.
What is a function prototype in C++?
A prototype is a declaration of a function without its body: the first line of the function followed by a semicolon, as in int add(int a, int b);. Placed above main, it lets main call add even though the definition, with the body, comes further down the file.
Can a function return more than one value in C++?
A function returns one value, but that value can be a struct with several members. Return the struct, and the caller reads each member from it.
Can you define a function inside another function in C++?
No: C++ allows a function to be defined only at namespace scope or inside a class, and MSVC, GCC and Clang all rejected one defined inside main; Clang said “function definition is not allowed here”. Define the function outside, above its caller, or write a lambda, which is the tool C++ gives for a small function inside another.
What are the types of functions in C++?
By origin, there are library functions, which come with the standard library and its headers, and the functions you write yourself. By result, a function either returns a value, as int add(int a, int b) does, or is declared void and returns nothing.
What is a recursive function?
A recursive function is a function that calls itself. It needs a condition that stops the calls, such as a countdown that ends at 0.
Sources
- Function declarationcppreference.com
- Unqualified name lookupcppreference.com
- [dcl.fct.def.general] Function definitionsC++ standard working draft
- [stmt.return] The return statementC++ standard working draft
- Default argumentscppreference.com
- [dcl.fct.default] Default argumentsC++ standard working draft
- Overload resolutioncppreference.com