Tutorials Logic, IN info@tutorialslogic.com

C++ Function and Class Templates

Generic C++ Contracts

A template generates type-specific code from one definition. Correct generic code depends on the operations it actually uses, not assumptions about one example type. Modern constraints make those requirements visible and produce errors closer to the call site.

A Constrained Function Template

std::totally_ordered documents the operations needed by clamp_value and rejects unsuitable types during overload resolution.

Clamp an ordered value

Clamp an ordered value
#include <concepts>
#include <iostream>

template<std::totally_ordered T>
T clamp_value(T value, T low, T high) {
    if (value < low) return low;
    if (high < value) return high;
    return value;
}

int main() {
    std::cout << clamp_value(15, 0, 10) << '\n';
    std::cout << clamp_value(2.5, 1.0, 4.0) << '\n';
}
Output
10
2.5
  • Compile with C++20 or newer.

Deduction and Specialization

Function arguments often allow type deduction; class template argument deduction works only where constructors or deduction guides provide enough information. Specialize behavior sparingly because overloads and policy objects are often easier to compose.

  • Keep template definitions visible.
  • Constrain requirements close to the interface.
  • Inspect code-size impact for many instantiations.

Instantiation and Constraints

Function templates are instantiated when used with concrete arguments. Definitions usually remain visible in headers unless explicit instantiation is designed deliberately. This can increase compile time, so avoid placing unrelated implementation or heavy includes in a widely used template header.

Use concepts or requires expressions to state semantic requirements such as sortable or contiguous input. Perfect forwarding and specialization are advanced tools with sharp edges; begin with value, reference, and const-reference parameters that express ownership plainly. Test multiple types, including one that should be rejected.

Make Template Requirements Visible

A template is checked again when it is instantiated with a concrete type. If the body uses ordering, addition, iteration, or copying, that operation is part of the real interface even when the function signature does not say so. C++20 concepts let the declaration state those requirements and produce diagnostics near the call.

Keep the requirement no stronger than the implementation needs. Requiring an exact concrete type or unnecessary operations makes a reusable template reject valid types.

Constrain a Maximum Function

Constrain a Maximum Function
#include <concepts>
#include <iostream>

template <typename T>
requires std::totally_ordered<T>
const T& maximum(const T& left, const T& right) {
    return left < right ? right : left;
}

int main() {
    std::cout << maximum(7, 11) << '\n';
}
Output
11

The concept documents and checks the ordering contract before the function body is instantiated.

Before you move on

Template Review

5 checks
  • The generic operation has a real cross-type use.
  • Requirements are documented or constrained.
  • Definitions are reachable during instantiation.
  • Error messages remain local.
  • Specialization is justified.

Template Failure Boundary

  • Hidden interface requirements

    A template fails at instantiation when its type does not support an operation used in the body. Constrain the template with a concept or document the required expressions.

Try this next

Template Constraint Practice

0 of 2 completed

  1. Write a max_value template, instantiate it with a custom type that has no ordering operator, then add the smallest C++20 concept that makes the requirement explicit. Compare the diagnostic before and after the requires clause.
  2. Verify the template with integers and strings, then explain which operation each instantiation must support. The template body is checked separately for each concrete type.

Template Questions

The compiler needs the full definition when it instantiates a template for a particular type.

It fails when the arguments do not provide enough type information or imply conflicting types.

Concepts state type requirements near the template and usually produce clearer errors than a failed instantiation deep inside its body.

Next Step
Next Practice

Finish the concept here, then reinforce it with hands-on coding, interview prep, or a tool that matches the topic.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.