Numeric Template Parameters and Array Class Templates in C++

Tmeplate parameters in C++ are not limited to types—they can also be compile-time constants, known as non-type (or numeric) template parameters. These enable powerful compile-time computations and fixed-size data structures.

Constraints on Non-Type Template Parameters

  • Must be compile-time constants—variables are not allowed.
  • Floaitng-point values cannot be used.
  • Class instances or pointers (except for specific cases like pointer-to-member) are disallowed.
  • Only integral, enumeration, or pointer/reference types with external linkage qualify.

Compile-Time Computation Example

The following demonstrates recursive template instantiation to compute the sum 1 + 2 + ... + N at compile time:

#include <iostream>

template <int N>
class CompileTimeSum {
public:
    static const int VALUE = CompileTimeSum<N - 1>::VALUE + N;
};

template <>
class CompileTimeSum<1> {
public:
    static const int VALUE = 1;
};

int main() {
    std::cout << "Sum 1..10 = " << CompileTimeSum<10>::VALUE << '\n';
    std::cout << "Sum 1..100 = " << CompileTimeSum<100>::VALUE << '\n';
    return 0;
}

Each recursive instentiation generates a distinct class type (CompileTimeSum<100>, CompileTimeSum<99>, etc.), but modern compilers optimize away unused intermediate types, retaining only the final computed constant.

Fixed-Size Array Template

A stack-allocated array class using a numeric template parameter for size:

// Array.h
#ifndef ARRAY_H
#define ARRAY_H

template <typename T, int Size>
class FixedArray {
protected:
    T elements[Size];

public:
    int length() { return Size; }
    int length() const { return Size; }

    bool get(int index, T& value) {
        if (index >= 0 && index < Size) {
            value = elements[index];
            return true;
        }
        return false;
    }

    bool set(int index, T value) {
        if (index >= 0 && index < Size) {
            elements[index] = value;
            return true;
        }
        return false;
    }

    T& operator[](int index) { return elements[index]; }

    virtual ~FixedArray() = default;
};

#endif

Heap-Allocated Dynamic Array Wrapper

A factory-based heap array that encapsulates dynamic allocation:

// HeapArray.h
#ifndef HEAP_ARRAY_H
#define HEAP_ARRAY_H

template <typename T>
class HeapArray {
private:
    T* data;
    int len;

    HeapArray(int n) : len(n), data(nullptr) {}
    bool initialize() { return (data = new(std::nothrow) T[len]) != nullptr; }

public:
    static HeapArray* create(int n) {
        auto instance = new(std::nothrow) HeapArray(n);
        if (instance && instance->initialize()) {
            return instance;
        }
        delete instance;
        return nullptr;
    }

    int length() const { return len; }
    T& operator[](int i) { return data[i]; }

    bool get(int i, T& val) {
        if (i >= 0 && i < len) {
            val = data[i];
            return true;
        }
        return false;
    }

    bool set(int i, const T& val) {
        if (i >= 0 && i < len) {
            data[i] = val;
            return true;
        }
        return false;
    }

    HeapArray& self() { return *this; }
    ~HeapArray() { delete[] data; }
};

#endif

Usage Example

#include <iostream>
#include "Array.h"
#include "HeapArray.h"

int main() {
    FixedArray<double, 5> arr1;
    for (int i = 0; i < arr1.length(); ++i)
        arr1[i] = i + 1;

    for (int i = 0; i < arr1.length(); ++i)
        std::cout << arr1[i] << '\n';

    const FixedArray<int, 10> arr2;
    std::cout << "Const array length: " << arr2.length() << '\n';

    auto* heapArr = HeapArray<int>::create(15);
    if (heapArr) {
        auto& arr = heapArr->self();
        for (int i = 0; i < arr.length(); ++i)
            arr[i] = i + 1;

        for (int i = 0; i < arr.length(); ++i)
            std::cout << arr[i] << '\n';

        delete heapArr;
    }

    return 0;
}

Tags: C++ Templates compile-time computation array class non-type template parameters

Posted on Mon, 28 Sep 2026 16:20:56 +0000 by foevah