Ready to practice?
Sign up to access interactive coding exercises and track your progress.
Working with std::array Size and Indices
Access elements and query size with bounds-checked and unchecked methods.
std::array length and indexing
Like std::vector, std::array uses unsigned types for lengths and indices, presenting similar challenges. However, std::array's constexpr nature provides additional compile-time options.
The length has type std::size_t
std::array is declared as:
template<typename T, std::size_t N>
struct array;
The length non-type template parameter N is std::size_t (unsigned). When defining an array, the length must be std::size_t or convertible to it.
Since the length must be constexpr, signed-to-unsigned conversion isn't narrowing—the compiler verifies safety at compile-time.
std::array uses size_type, which is always std::size_t
Like std::vector, std::array defines a nested typedef size_type for lengths and indices. Unlike std::vector, std::array's size_type is ALWAYS std::size_t (no customization possible).
The template parameter uses std::size_t explicitly because size_type isn't defined yet at that point. Everywhere else uses size_type.
Getting array length
Three common approaches:
Option 1: size() member function
#include <array>
#include <iostream>
int main()
{
constexpr std::array stats{ 25, 30, 18, 22 };
std::cout << "Elements: " << stats.size() << '\n';
return 0;
}
Returns unsigned size_type.
Option 2: std::size() non-member function (C++17)
#include <array>
#include <iostream>
int main()
{
constexpr std::array stats{ 25, 30, 18, 22 };
std::cout << "Elements: " << std::size(stats) << '\n';
return 0;
}
Calls the size() member function, returning unsigned size_type.
Option 3: std::ssize() non-member function (C++20)
#include <array>
#include <iostream>
int main()
{
constexpr std::array stats{ 25, 30, 18, 22 };
std::cout << "Elements: " << std::ssize(stats) << '\n';
return 0;
}
Returns a large signed integral type (typically std::ptrdiff_t).
Constexpr length from all three methods
Because std::array length is constexpr, all three functions return constexpr values even for non-constexpr arrays:
#include <array>
#include <iostream>
int main()
{
std::array bonuses{ 50, 75, 100, 150 }; // Not constexpr
constexpr int count{ std::size(bonuses) }; // OK: result is constexpr
std::cout << "Count: " << count << '\n';
return 0;
}
The conversion from constexpr std::size_t to int isn't narrowing.
This doesn't work for array parameters passed by reference due to a language defect (addressed in C++23):
#include <array>
void show(const std::array<int, 5>& arr)
{
constexpr int count{ std::size(arr) }; // Error pre-C++23!
}
Workaround: use a function template with a length non-type parameter.
Subscripting with operator[] or at()
Both operator[] (no bounds checking) and at() (runtime bounds checking) expect size_type indices:
#include <array>
#include <iostream>
int main()
{
constexpr std::array rewards{ 10, 25, 50, 100 };
std::cout << rewards[2] << '\n'; // No bounds checking
std::cout << rewards.at(2) << '\n'; // Runtime bounds checking
return 0;
}
With constexpr indices, conversion to std::size_t isn't narrowing. With non-constexpr signed indices, you'll get narrowing warnings (same issue as std::vector).
Compile-time bounds checking with std::get()
For constexpr indices, use std::get() for compile-time bounds checking:
#include <array>
#include <iostream>
int main()
{
constexpr std::array rewards{ 10, 25, 50, 100 };
std::cout << std::get<2>(rewards) << '\n'; // OK: valid index
std::cout << std::get<7>(rewards) << '\n'; // Compile error: index out of range
return 0;
}
std::get() uses a non-type template argument for the index and static_asserts that it's within bounds. Since template arguments must be constexpr, this only works with constexpr indices.
Summary
Length type: The std::array length template parameter N has type std::size_t (unsigned). Since the length must be constexpr, signed-to-unsigned conversion isn't narrowing because the compiler verifies safety at compile-time.
size_type is always std::size_t: Unlike std::vector which can customize size_type, std::array's size_type is always std::size_t. The template parameter uses std::size_t explicitly because size_type isn't defined yet at that point.
Three ways to get length: The size() member function, std::size() non-member function (C++17), and std::ssize() non-member function (C++20). All work with std::array, with std::ssize() returning a signed type.
Constexpr length: All three length functions return constexpr values for std::array, even when the array itself isn't constexpr. This allows using the length in constant expressions and static assertions.
Subscripting: Both operator[] (no bounds checking) and at() (runtime bounds checking) expect size_type indices. With constexpr indices, conversion to std::size_t isn't narrowing. With non-constexpr signed indices, you may get narrowing warnings.
Compile-time bounds checking: std::get<N>() provides compile-time bounds checking for constexpr indices. It uses a non-type template argument for the index and static_asserts validity, preventing out-of-bounds access at compile-time.
Language defect (pre-C++23): Getting the constexpr length of array parameters passed by reference doesn't work prior to C++23. Workaround: use a function template with a length non-type parameter.
The key insight is that std::array's constexpr length enables compile-time operations and safety checks that aren't possible with runtime-sized arrays like std::vector.
Working with std::array Size and Indices - Quiz
Test your understanding of the lesson.
Practice Exercises
std::array Length and Indexing
Practice working with std::array size and indexing. Learn about compile-time size, bounds checking, and safe access patterns.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!