The new static constexpr std::integral_constant idiom
- Home
- Career
- Developer blog
- The new static constexpr std::integral_constant idiom
3 min read — by Jonathan Müller
The size of std::array<T, N>
is known at compile-time given the type. Yet it only provides a regular .size()
member function:
template <typename T, std::size_t N>
struct array {
constexpr std::size_t size() const {
return N;
}
};
std::array::size
This is annoying if you're writing generic code that expects some sort of compile-time sized range.
template <typename Rng>
void algorithm(Rng const& rng) {
constexpr auto a = Rng::size(); // error, std::array has no static size
constexpr auto b = rng.size(); // error, not a constant expression
constexpr auto c = std::tuple_size<Rng>::value; // okay, but ugly
}
It would be really nice if std::array::size
were a static
member function instead:
template <typename T, std::size_t N>
struct array {
static constexpr std::size_t size() {
return N;
}
};
std::array::size
Now we can just use ::size()
to get the size of an array without breaking existing code: You can still call static
member functions with .
syntax; foo.static_member(args)
is equivalent to std::remove_cvref_t<decltype(foo)>::static_member(args)
. There are MISRA guidelines against it and a clang-tidy check that complains, but it is really useful for generic code.
However, sometimes even Rng::size()
isn't enough. Suppose we want to have a std::integral_constant
as the result, so we can do type-based metaprogramming. Sure, we can then write std::integral_constant<std::size_t, Rng::size()>{}
, but that's a lot to type. It would be really convenient if std::array
had that directly, as that is the "most const" version of a size:
template <typename T, std::size_t N>
struct array {
static constexpr std::integral_constant<std::size_t, N> size = {};
};
std::array::size
?Now we can write array::size
and get a std::integral_constant
that represents the size. But we've broken all code that assumed .size()
or ::size()
?
You'd think so, but no: std::integral_constant
has a call operator!
template <typename T, T Value>
struct integral_constant {
constexpr T operator()() const {
return Value;
}
};
std::integral_constant::operator()
So with a single member, we support:
array::size
, which results in astd::integral_constant
object.array::size()
, which calls theoperator()
on thestd::integral_constant
and returns astd::size_t
.array_obj.size()
, which is the same as above and returns astd::size_t
, just as a member function.
Now that is nice!
The library evolution group of the C++ committee is considering that idiom for all new standard library components with constant sizes, like std::simd
, or std::inplace_vector::capacity
(formerly std::static_vector::capacity
). Of course, we can't actually change std::array
due to ABI or something...
Do you have feedback? Send us a message at devblog@think-cell.com

- Enough time to make sure that every detail of your solution is perfect
- Become part of n international team of brilliant minds
- No scheduled meetings