Reputation: 13
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.
Upvotes: 0
Views: 84
Reputation: 596332
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];
};
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];
};
Upvotes: 1