Skip to main content

if constexpr, NTTPs, and Compile-Time Data

advanced11 min readLesson 141 of 204

Non-type template parameters turn sizes and array lengths into types. Combined with if constexpr, they carry whole tables into compile time.

Non-type template parameters (NTTPs)

Template parameters can be values: sizes, enumerations, pointers โ€” anything constant-expression-able. The most common: std::size_t:

template <std::size_t N> struct Ring {
    int data_[N]{};
    std::size_t head_ = 0;
    void push(int v) { data_[head_++ % N] = v; }
    static constexpr std::size_t capacity() { return N; }
};

Every Ring<8> and Ring<1024> is a distinct type with zero heap allocations and a compile-time-known capacity.

Array-bound NTTP โ€” free string lengths

Deducing N from an array reference gives you the literal's length for free: template <std::size_t N> constexpr std::size_t strLen(const char (&s)[N]) { return N - 1; } โ€” strLen("abcd") is 4, computed at compile time, no strlen.

Partial specialization over NTTPs

The two compose: Capacity<std::array<T, N>> peels the size out of the type โ€” the standard library's own tuple_size works this way.

Watch out: each distinct N instantiates a distinct type. A Ring<8> is not a Ring<9>; if you need runtime-variable capacity, that is a std::vector job, not an NTTP job.

Now practice

if constexpr and NTTPsType-branched formatting, a fixed ring buffer, and the array-bound NTTP trick.3 challenges ยท ยท ~20 min