0

I have a custom implementation for arrays with arbitrary upper and lower bounds. Now I want to be able to freely convert between arrays of the same type, as long as they have the same length. In code it looks like this:

template<typename T, int L, int H>
class Array{
    public:
        // stuff ...

        operator Array<T, int lb, int hb>& () {
            auto converted = Array<T, lb, hb>;
            converted.actualArray = actualArray;
            converted.offset = lb;
            return *converted;
        }
    private:
        T actualArray[H - L + 1];
        int offset = 0 - L;
}

As you can see, the class needs to convert to itself. As you can probably also see, I am quite the noob at C++, as the error I'm given appears to be a syntax one:

wrong number of template arguments (2, should be 3)
operator Array<T, int lb, int hb>& () {
                                ^

'<expression error>' does not name a type
operator Array<T, int lb, int hb>& () {
^

What am I doing wrong, that my operator's return type is not recognized? I really hope it's not a simple typo, that would be stupid.

  • Did you call it with 3 arguments? – Nyque Jun 25 '18 at 23:46
  • Give an example of input and output. This kind of clarifies. Are you trying to overload & operator? Your function signature doesn't seem right. It shoud be something like Array operator & (Array X). Also need code where that class function is called. – Nguai al Jun 25 '18 at 23:54
  • Possible duplicate of [What are the basic rules and idioms for operator overloading?](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading) – Joseph D. Jun 26 '18 at 00:07
  • Even if you could get the parameters right, it still wouldn't work since you can't assign arrays to arrays, you need to copy the elements instead, such as with `std:copy()` or `std::copy_n()`. – Remy Lebeau Jun 26 '18 at 00:36
  • Yes to what RemyLebeau stated -- why does this code seem over-engineered? A simple `std::copy` and an adjustment of the limits seems all you really need to do. Looking at it myself, if you never explained what this code did, it wouldn't be simple to figure out what it was doing. – PaulMcKenzie Jun 26 '18 at 00:38

1 Answers1

1

You need a second set of template parameters for the operator itself, so it can be called with different template values than the main class uses.

Even if you could get the template parameters right, it still wouldn't work since you can't assign a raw array to another raw array. You need to copy the elements instead, such as with std:copy() or std::copy_n().

Try something more like this:

#include <algorithm>

template<typename T, size_t L, size_t H>
class Array
{
public:
    static_assert(H >= L);
    static const size_t Low = L;
    static const size_t High = H;
    static const size_t Length = (H - L + 1);

    // stuff ...

    template<size_t Lb, size_t Hb>
    operator Array<T, Lb, Hb>() const
    {
        static_assert(Length == Array<T, Lb, Hb>::Length);
        Array<T, Lb, Hb> converted;
        std::copy_n(actualArray, Length, converted.actualArray);
        return converted;
    }

    // just to show that you don't need an offset member...

    T& operator[](size_t idx)
    {
        return actualArray[idx - L];
    }

    T operator[](size_t idx) const
    {
        return actualArray[idx - L];
    }

    template<typename, size_t, size_t>
    friend class Array;

private:
    T actualArray[Length];
};

Live Demo

Alternative, you could define a copy constructor that accepts multiple Array types of the same array size, and then you don't need the conversion operator anymore:

#include <algorithm>

template<typename T, size_t L, size_t H>
class Array
{
public:
    static_assert(H >= L);
    static const size_t Low = L;
    static const size_t High = H;
    static const size_t Length = (H - L + 1);

    // stuff ...

    Array() = default;

    template<size_t Lb, size_t Hb>
    Array(const Array<T, Lb, Hb> &src)
    {
        static_assert(Length == Array<T, Lb, Hb>::Length);
        std::copy_n(src.actualArray, Length, actualArray);
    }

    // just to show that you don't need an offset member...

    T& operator[](size_t idx)
    {
        return actualArray[idx - L];
    }

    T operator[](size_t idx) const
    {
        return actualArray[idx - L];
    }

    template<typename, size_t, size_t>
    friend class Array;

private:
    T actualArray[Length];
};

Live Demo

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770