0

I like to think I have grasped most aspects of object oriented programming but C++ has yet again presented me with an unexpected result. While creating a static array class in C++ (much like std::array), I added the + operator and it gave me a very strange compiler error.

Has anyone encountered this situation before?

#pragma once

#ifdef NDEBUG
    #define __ESL_Array_AssertCorrectInitSize(array, init)
#else
    #define __ESL_Array_AssertCorrectInitSize(array, init) if (init.size() != array->Size()) throw ESL::ArrayInitializationException("std::initializer_list size is different than static size");
#endif // NDEBUG

#include<cstdint>
#include<utility>
#include<stdexcept>

namespace ESL
{
    class ArrayInitializationException : public std::runtime_error
    {
    public:
        ArrayInitializationException(const std::string &msg): std::runtime_error(msg) {}
    };

    template <typename T, uint32_t S>
    class Array
    {
    public:
        Array(): m_data() {}

        Array(const T (&arr)[S]):
            m_data()
        {
            const T *src_itr = arr;
            T *dst_itr = m_data;

            for (uint32_t i = 0; i < S; ++i)
                *(dst_itr++) = *(src_itr++);
        }

        Array(std::initializer_list<T> list):
            m_data()
        {
            __ESL_Array_AssertCorrectInitSize(this, list)

            const T *src_itr = list.begin();
            T *dst_src = m_data;

            for (uint32_t i = 0; i < S; ++i)
            {
                *(dst_src++) = *(src_itr++);
            }
        }

        Array(const Array &a):
            m_data()
        {
            const T *src_itr = a.m_data;
            T *dst_itr = m_data;

            for (uint32_t i = 0; i < S; ++i)
                *(dst_itr++) = *(src_itr++);
        }

        Array(Array &&a):
            m_data()
        {
            T *src_itr = a.m_data;
            T *dst_itr = m_data;

            for (uint32_t i = 0; i < S; ++i)
                *(dst_itr++) = std::forward<T>(*(src_itr++));
        }

        Array &operator=(const Array &a)
        {
            const T *src_itr = a.m_data;
            T *dst_itr = m_data;

            for (uint32_t i = 0; i < S; ++i)
                *(dst_itr++) = *(src_itr++);
            
            return *this;
        }

        Array &operator=(Array &&a)
        {
            const T *src_itr = a.m_data;
            T *dst_itr = m_data;

            for (uint32_t i = 0; i < S; ++i)
                *(dst_itr++) = std::forward<T>(*(src_itr++));
            
            return *this;
        }

        constexpr uint32_t Size() const { return S; }

        const T &operator[](uint32_t index) const { return m_data[index]; }
        T &operator[](uint32_t index) { return m_data[index]; }

        const T *begin() const { return m_data; }
        T *begin() { return m_data; }
        const T *end() const { return m_data + S; }
        T *end() { return m_data + S; }

        bool operator==(const Array &a) const
        {
            const T *itr1 = m_data;
            const T *itr2 = a.m_data;

            for (uint32_t i = 0; i < S; ++i)
            {
                if (*(itr1++) != *(itr2++)) return false;
            }

            return true;
        }

        bool operator!=(const Array &a) const
        {
            const T *itr1 = m_data;
            const T *itr2 = a.m_data;

            for (uint32_t i = 0; i < S; ++i)
            {
                if (*(itr1++) != *(itr2++)) return true;
            }

            return false;
        }

        template <uint32_t S2>
        Array<T, S + S2> operator+(const Array<T, S2> &a) const
        {
            Array<T, S + S2> res;

            const T *src_itr = m_data;
            T *dst_itr = res.m_data;

            for (uint32_t i = 0; i < S; ++i)
                *(dst_itr++) = *(src_itr++);
            
            src_itr = a.m_data;

            for (uint32_t i = 0; i < S2; ++i)
                *(dst_itr++) = *(src_itr++);

            return res;
        }

    private:
        T m_data[S];
    };
}

If you need any more code, I'd be willing to post the entire file. I appreciate any input! Thanks!

EDIT: Just realized I forgot the compiler output:

In instantiation of ‘ESL::Array<T, (S + S2)> ESL::Array<T, S>::operator+(const ESL::Array<T, S2>&) const [with unsigned int S2 = 2; T = double; unsigned int S = 3]’:
[build] /home/joshlengel/Dev/C++/ESL/Main.cpp:10:20:   required from here
[build] /home/joshlengel/Dev/C++/ESL/ESL/include/collection/Array.h:135:30: error: ‘double ESL::Array<double, 5>::m_data [5]’ is private within this context
[build]   135 |             T *dst_itr = res.m_data;
[build]       |                          ~~~~^~~~~~
[build] /home/joshlengel/Dev/C++/ESL/ESL/include/collection/Array.h:149:11: note: declared private here
[build]   149 |         T m_data[S];
J. Lengel
  • 570
  • 3
  • 16

1 Answers1

1

The reason is for the class, Array<double, 2> and Array<double, 3> are completely two different classes. This is why it says that you cant access private members. For this you either have to make the m_data member public, or use begin() like so,

template <uint32_t S2>
Array<T, S + S2> operator+(const Array<T, S2>& a) const
{
    Array<T, S + S2> res;

    // You can ditch the for loops and use std::copy instead. It *can* be more efficient.
    std::copy(begin(), end(), res.begin());
    std::copy(a.begin(), a.end(), res.begin() + S);

    return res;
}
D-RAJ
  • 3,263
  • 2
  • 6
  • 24
  • `std::memcpy` is not a good suggestion for an array of any T type. `memcpy` is only valid if the type is trivially_copyable, otherwise doing this would be undefined behavior (for example, an `Array` would not work correctly). You're better off using `std::copy` or something else instead. – Human-Compiler Jan 29 '21 at 17:58
  • @Human-Compiler Yeah got that later. I swapped it with `std::copy`. – D-RAJ Jan 29 '21 at 18:00
  • is std::copy explicitly instantiated with std::memcpy for trivially copyables? Is that what makes it more efficient? – J. Lengel Jan 29 '21 at 20:00
  • @J.Lengel I think this would answer that question: https://stackoverflow.com/a/9980859/11228029 – D-RAJ Jan 29 '21 at 20:03