Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A non-type template parameter (NTTP) is a template parameter that expects a compile-time constant value rather than a type. When instantiated, the compiler substitutes the parameter with the provided constant expression, making the value an integral part of the generated type or function signature.

Syntax

Non-type template parameters are declared by specifying a concrete type (or auto) in the template parameter list, followed by an identifier.
#include <cstddef>

// Class template with a type parameter (T) and a non-type parameter (N)
template <typename T, std::size_t N>
class StaticArray {
    T elements[N]; 
};

// Function template with a non-type parameter
template <int Offset, typename T>
T apply_offset(T value) {
    return value + Offset;
}

// Instantiation
StaticArray<int, 256> buffer;
int result = apply_offset<10>(5);

Permitted Types

The types allowed for non-type template parameters are strictly regulated by the C++ standard and have expanded across standard revisions. Prior to C++17, non-type template parameters were restricted to:
  • Integral types (int, char, long, std::size_t, bool, etc.)
  • Enumeration types (enum and enum class)
  • Pointers or references to objects, functions, or class members (the referenced entity was required to have static storage duration and external or internal linkage)
  • std::nullptr_t
Since C++17, the linkage requirement for pointers and references was removed. Pointers and references can now bind to objects with no linkage (such as static local variables), provided the object still possesses static storage duration. Since C++20, restrictions were further relaxed to include structural types, allowing:
  • Floating-point types (float, double)
  • Literal class types. To qualify as a structural type, the class must have constexpr constructors, no virtual base classes, no virtual functions, all base classes and non-static data members must be public and structural, and neither the class nor its base classes may have any mutable non-static data members.
// C++20: Floating-point NTTP
template <double Threshold>
bool is_above(double value) {
    return value > Threshold;
}

// C++20: Literal class type NTTP
struct Point {
    int x;
    int y;
};

template <Point P>
struct Cursor {
    static constexpr int x_pos = P.x;
};

Cursor<Point{10, 20}> my_cursor;

auto Non-Type Template Parameters (C++17)

Since C++17, the auto keyword can be used to instruct the compiler to deduce the type of the non-type template parameter directly from the provided argument.
template <auto Value>
struct Constant {
    using Type = decltype(Value);
    static constexpr Type value = Value;
};

Constant<42> c1;       // Parameter deduced as int; instantiated type is Constant<42>
Constant<'A'> c2;      // Parameter deduced as char; instantiated type is Constant<'A'>
Constant<true> c3;     // Parameter deduced as bool; instantiated type is Constant<true>

Technical Constraints

  1. Compile-Time Evaluation: The argument passed to a non-type template parameter must be a constant expression (constexpr). It cannot be a variable whose value is determined at runtime.
  2. Value Category and Mutability: The properties of an NTTP within the template definition depend on its type:
    • Non-reference types (e.g., int, enum, pointers): The parameter acts as a prvalue (pure rvalue). It is strictly read-only, and its address cannot be taken.
    • Reference types (e.g., int&, MyClass&): The parameter acts as an lvalue. You can take its address (which yields the address of the bound object), and you can modify the referenced object provided the reference is not const.
  3. Type Identity: Instantiations with different non-type template arguments result in distinct, incompatible types. For example, StaticArray<int, 5> and StaticArray<int, 6> are completely separate types in the C++ type system.
  4. String Literals (Pre-C++20): Passing string literals directly (e.g., Template<"string">) is prohibited before C++20 because string literals have no linkage and their addresses are not guaranteed to be unique across translation units. C++20 allows string-like NTTPs by passing them through structural wrapper classes that store the string characters as an array.
Master C++ with Deep Grasping Methodology!Learn More