Are arrays covariant in size?

Is there a way to use the new type std::arraypolymorphically in array size? That is, if I have a function of the form

void DoSomething(std::array<int, 5>& myArray) {
    /* ... */
}

Then is it mathematically defined correctly to perform the following (even if it is not legal C ++ code?)

std::array<int, 10> arr;
DoSomething(arr);

Imof this is mathematically correct, is there a way to write std::arrayso that its array elements are contiguous and this code compiles? The only method I could think of is to have some kind of weird template metaprogram where it std::array<T, N+1>inherits from std::array<T, N>, but I don't believe what causes the elements of the array to be contiguous.

+3
source share
3 answers

Directly? No.

- , , :

#include <array>
#include <cstddef>

template <typename T, std::size_t N>
struct ref_array_of_at_least
{
    template <std::size_t M>
    ref_array_of_at_least(T (&a)[M])
        : data_(a)
    {
        static_assert(M >= N, "Invalid size");
    }

    template <std::size_t M>
    ref_array_of_at_least(std::array<T, M>& a)
        : data_(&a[0])
    {
        static_assert(M >= N, "Invalid size");
    }

    T* data_;
};

:

void f(ref_array_of_at_least<int, 5>) { }

int main()
{
    std::array<int, 5> x;
    std::array<int, 6> y;
    std::array<int, 4> z;
    f(x); // ok
    f(y); // ok
    f(z); // fail
}

( operator[] .. ref_array_of_at_least, , , , , .)

+5

, :

#include <iostream>

template <typename T, int N>
struct Array
{
    Array() { for (int i = 0; i < N; ++i) x[i] = 0; }

    template <int N2>
    operator Array<T, N2>&()
    {
        // for safety, static assert that N2 < N...
        return reinterpret_cast<Array<T, N2>&>(*this);
    }

    int size() const { return N; }
    T x[N];

    friend std::ostream& operator<<(std::ostream& os, const Array& a)
    {
        os << "[ ";
        for (int i = 0; i < N; ++i) os << a.x[i] << ' ';
        return os << ']';
    }
};


void f(Array<int, 5>& a)
{
    a.x[a.size() - 1] = -1;
}

int main()
{
    Array<int, 10> a;
    std::cout << a << '\n';
    f(a);
    std::cout << a << '\n';
}

: . , - - :

template <size_t N2>
Array<T,N2>& slice(size_t first_index)
{
    return *(Array<T,N2>*)(data() + first_index);
}

// usage...
f(a.slice<5>(3));  // elements 3,4,5,6,7.

( : -/)

+2

, :

// Hide this function however you like: "detail" namespace, use "_detail"
// in the name, etc.; since it not part of the public interface.
void f_detail(int size, int *data) {
  use(data, /* up to */ data + size);
}

int const f_min_len = 5;

template<int N>
void f(int (&data)[N]) {
  static_assert(N >= f_min_len);
  f_detail(N, data);
}

template<int N>
void f(std::array<int, N> &data) {
  static_assert(N >= f_min_len);
  f_detail(N, &data[0]);
}

, . int ( ) const, .

0

Source: https://habr.com/ru/post/1786306/


All Articles