Step 6 of 8
Values as template parameters
Template parameters don't have to be types. A non-type template parameter is a compile-time value, most often a size:
#include <cstddef>
#include <iostream>
template <typename T, std::size_t N>
class History {
public:
void record(const T& v) {
items_[next_ % N] = v; // overwrite the oldest once full
next_++;
}
std::size_t stored() const { return next_ < N ? next_ : N; }
static constexpr std::size_t capacity() { return N; }
private:
T items_[N]{};
std::size_t next_ = 0;
};
int main() {
History<int, 3> h;
for (int i = 1; i <= 5; i++) h.record(i * 10);
std::cout << h.stored() << " of " << h.capacity() << "\n";
std::cout << History<char, 16>::capacity() << "\n";
std::cout << "bigger N, bigger object: " << (sizeof(History<int, 100>) > sizeof(History<int, 3>)) << "\n";
}
3 of 3
16
bigger N, bigger object: 1
How it works
std::size_t Nis a parameter of the template, fixed when you writeHistory<int, 3>. Inside the class it's a constant, soT items_[N]is a normal fixed-size array.- The array lives inside the object. There's no heap allocation at all, which is why
sizeofgrows withN: aHistory<int, 100>object holds 100 ints plus a counter. History<int, 3>andHistory<int, 100>are different types. You can't assign one to the other.static constexpr std::size_t capacity()belongs to the class, not an object, so it can be called asHistory<char, 16>::capacity().
This is exactly how std::array<int, 5> works.
Your task: a fixed-size stack
Keep count_ as the number of items. push writes to items_[count_] and increments, unless count_ == N, in which case it returns false. pop decrements first, then returns items_[count_].
Your turn: write template <typename T, std::size_t N> class FixedStack backed by a plain array T items_[N]:
bool push(const T& v): returnsfalse(and does nothing) when fullT pop(): removes and returns the top (assume non-empty)std::size_t size() const,bool full() conststatic constexpr std::size_t capacity() { return N; }