← C++, End to End

C++, End to End

Function Overloading and Function Templates

C++ lets you write several functions with the same name as long as their parameter lists differ (overloading), and lets you write one function that works across many types without duplicating code (templates). They solve related but different problems, and it's worth being precise about which one you're reaching for.

Function overloading

Two functions can share a name if they differ in the number or types of their parameters. The compiler picks the best match at compile time based on the argument types at each call site, this is resolved statically, not at runtime.

c++ · live, editable, runnableOpen in Compiler Explorer ↗

Overload resolution and ambiguity

The compiler ranks candidate overloads by how "exact" the match is: an exact type match beats a promotion (like char to int), which beats a standard conversion (like int to double), which beats a user-defined conversion. If two overloads are an equally good match for a given call, the call is ambiguous and fails to compile rather than picking one arbitrarily.

c++ · live, editable, runnableOpen in Compiler Explorer ↗

Default arguments

A parameter can have a default value, letting callers omit it. Default arguments interact with overloading in a way worth knowing: they can create ambiguity with an otherwise-valid overload if the resulting call could match either one.

c++ · live, editable, runnableOpen in Compiler Explorer ↗

Function templates

Overloading still means writing out every version by hand. A function template lets the compiler generate the version it needs, for whatever type you actually call it with, from a single generic definition:

c++ · live, editable, runnableOpen in Compiler Explorer ↗

T here is a template parameter, a placeholder for a type the compiler fills in based on the arguments at each call site. This is called template argument deduction, and it's usually implicit: you don't write max_of<int>(3, 7), the compiler figures out T = int from the arguments themselves.

Why templates aren't "generics with extra steps"

In languages with runtime generics, one compiled version of a generic function handles every type, with type information checked or erased at runtime. C++ templates work completely differently: for every distinct set of template arguments you actually use, the compiler generates ("instantiates") a separate, fully concrete version of the function at compile time. max_of<int> and max_of<double> are two entirely different functions in the final binary, each optimized as if you'd hand-written it for that specific type.

  • This means templates have zero runtime overhead compared to hand-written type-specific code: there's no dispatch, no boxing, nothing to look up at runtime.
  • It also means an error inside a template body often doesn't show up until the template is actually instantiated with a specific type, which is why template error messages have a well-earned reputation for being long and confusing: the compiler is reporting an error in a specific instantiation, not the generic template text you wrote.
  • And it means heavy template use can noticeably increase compile times and binary size, since every distinct instantiation is genuinely separate generated code.
Try it yourself: turn three overloads into one template

These three overloads do the same thing for three different types. Replace them with a single function template, then confirm all three call sites still work unchanged.

c++ · live, editable, runnableOpen in Compiler Explorer ↗