Example
void foo1(int*);
void foo2(int[42]);
void foo3(int[]);
void foo4(int(&)[42]);
int main() {
int a[42]{};
foo1(a); // ok
foo2(a); // ok
foo3(a); // ok
foo4(a); // ok
}
Puzzle
- Can you implement
array_size
which returns the size of given array?
[[nodiscard]] consteval auto array_size(auto); // TODO
static_assert(1uz == [] { bool a[]{{}}; return array_size(a); }());
static_assert(3uz == [] { int a[]{{}, {}, {}}; return array_size(a); }());
static_assert(42uz == [] { int a[42]{}; return array_size(a); }());
static_assert(0uz == array_size(std::array<bool, 0>{}));
static_assert(3uz == array_size(std::array<int, 3>{}));
static_assert(42uz == array_size(std::array<char, 42>{}));
static_assert(1uz == array_size(std::vector{1}));
static_assert(3uz == array_size(std::vector{1, 2, 3}));
Solutions
[[nodiscard]] consteval auto array_size(auto&& x) {
return std::size(x);
}
template< typename T, size_t N > constexpr size_t array_size (T (&) [N]){ return N; }
template< typename T> constexpr auto array_size (T && t){ return t.size(); }
[[nodiscard]] consteval auto array_size(auto&& arr){
if constexpr(std::is_array_v<std::remove_cvref_t<decltype(arr)>>) {
return sizeof(arr) / sizeof(arr[0]);
}
else {
return std::size(arr);
}
}
template <typename T, auto N>
[[nodiscard]] consteval auto array_size(T(&)[N]) { return N; }
template <typename T>
requires requires { std::declval<T>().size(); }
[[nodiscard]] constexpr auto array_size(T&& t) {
return t.size();
}
template <typename T, std::size_t N>
[[nodiscard]] consteval auto array_size(T(&)[N]) { return N; }
template <typename T>
requires requires { std::declval<const T &>().size(); }
[[nodiscard]] consteval auto array_size(const T& array) { return array.size(); }
[[nodiscard]] consteval auto array_size(const auto& t) {
return std::size(t);
}
template<typename T, std::size_t N>
[[nodiscard]] consteval std::size_t array_size(T(&)[N]){
return N;
}
[[nodiscard]] consteval std::size_t array_size(auto x){
return std::size(x);
}
template <std::size_t sz>
[[nodiscard]] consteval auto array_size(const auto (& my_array)[sz])
{
return sz;
}
template <class T, std::size_t sz>
[[nodiscard]] consteval auto array_size(const std::array<T, sz>&)
{
return sz;
}
[[nodiscard]] consteval auto array_size(const auto& v)
{
return std::size(v);
}
template <class T, std::size_t N>
[[nodiscard]] consteval auto array_size(T (&)[N]){
return N;
}
[[nodiscard]] consteval auto array_size(auto aa){
if constexpr (requires { aa.size(); }) {
return aa.size();
}
}
[[nodiscard]] consteval auto array_size(auto &&ar){
if constexpr (requires {ar.size();})
return ar.size();
else
return sizeof(ar) / sizeof(ar[0]);
}