I would like to have a concept that checks if a type is a container
of fixed length. The type could be a C-style array, a std::array
, a std::span
or a custom-made container. I can check for the
container condition as shown in the code below, but I cannot get it to
check for the length condition.
template <typename T, size_t N>
concept fixed_container =
requires (T const& t)
{
{std::size(t)} -> std::same_as<size_t>;
{std::begin(t)};
{std::end(t)};
}
// && std::declval<T>().size() == N // Error: 'declval() must not be used!'
// && T::size() == N // Error: 'call to non-static member function without an object argument'
;
// These should all be correct
static_assert( fixed_container<std::array<double, 3>, 3>);
static_assert(!fixed_container<std::array<double, 3>, 4>);
static_assert( fixed_container<std::span<double, 3>, 3>);
static_assert(!fixed_container<std::span<double, 3>, 4>);
static_assert( fixed_container<double[3], 3>);
static_assert(!fixed_container<double[3], 4>);
Any ideas?
EDIT: The block
requires (T const& t)
{
{std::size(t)} -> std::same_as<size_t>;
{std::begin(t)};
{std::end(t)};
}
can be replaced by a single line
std::ranges::sized_range<T>
It is much simpler than previous answers. Just test each type you want to support:
template <typename T, size_t N>
concept fixed_container = std::ranges::sized_range<T> &&
( std::extent_v<T> == N || // var[N]
T::extent == N || // std::span
std::tuple_size<T>::value == N ); // Tuple-like types, i.e. std::array