Skip to content

Latest commit

 

History

History
63 lines (46 loc) · 2.68 KB

array.md

File metadata and controls

63 lines (46 loc) · 2.68 KB

array

array is a container encapsulating fixed sized arrays and do not decay to T* unlike C arrays. It provides iterators, element-wise access, memeber types, everything you would expect from a standard library container. Its templated on the type, typename T, and the size, std::size_t N. But it has a few oddities; the constructor and assignment operator are implicitly declared, and how are begin() and end() defined when the size is zero?

Sample

To construct an array we use aggregate-initialisation, but this leads to a few potential problems. We can initialise values with less than three elements. In this scenario, the unspecified elements are value-initialised, which in the case of double falls back to zero-initialisation.

template <typename Value, std::size_t N>
void print(const learn::array<Value, N>& values) {
    for (const auto& value: values) {
        std::cout << value << ' ';
    }

    std::cout << '\n';
}

learn::array<int, 3> values = {0, -2, 3};
print(values); // 0 -2 3

values = {3, 1};
print(values) // 3 1 0

This means that when we construct an array with no values, value-initialisation is performed on all elements.

learn::array<double, 3> values2;

print(values) // 0.0 0.0 0.0

How it works

array is a struct, containing a C-style array. We can perform aggregate-initialisation as array has,

  • no private or protected non-static data members
  • no user-provided, inherited, or explicit constructors (explicitly defaulted or deleted constructors are allowed)
  • no virtual, private, or protected (since C++17) base classes
  • no virtual member functions

. We define internal C-style array so that it contains one element when the size is zero. This lets array have a size of zero and have defined behaviour. This is in contrast to ISO C / C++ which does not allow arrays of size zero.

template <typename Value, std::size_t Size>
struct array {
    using value_type = Value;
    
    // some type declerations... 
    // some member function declerations...

    value_type elems_[Size > 0 ? Size : 1];
};

By defining the size of elems_ this way we can define the begin and end iterators, which are valid even when Size == 0.

    // some member function declerations...

    constexpr iterator begin() noexcept { return iterator(elems_); }

    constexpr iterator end() { return iterator(elems_ + Size); }
    value_type elems_[Size > 0 ? Size : 1];
};