I have a peculiar problem. I want to create classes with variable length arrays in them. I don't want to allocate the arrays on the heap for the reasons of locality (the code slows down by a factor of 2 when I do). I don't want to use a virtual function because I don't want to pay for a function call. The following code works (on my compiler/platform), but with a caveat.
include <iostream>
include <boost/array.hpp>
struct Base
{
Base(size_t s):
size(s) {}
int& up(size_t i) { return *(reinterpret_cast<int*>((&size) + 1) + i); }
size_t size;
};
template<size_t sz>
struct Derived: public Base
{
boost::array<int, sz> data;
Derived(): Base(sz) {}
};
int main()
{
Derived<5> d5;
d5.data[2] = 1234;
Base* b = &d5;
std::cout << b->up(2) << std::endl;
}
This is incredibly ugly; the reinterpret_cast<...> is a red flag. Moreover, the caveat is that this fails if I change size_t to, say, short unsigned (I guess the compiler pads the class).
So the question is: is there a way to make this portable? Is there a way to determine from Base where the first member variable will sit in its derived class?
Just an idea that came to my mind: let the Derived constructor store a pointer to its data inside a Base member.
struct Base
{
protected:
size_t size;
int * array;
Base(size_t s, int * arr):
size(s), array(arr)
{ }
public:
int& up(size_t i) { return array[i]; }
size_t getSize() { return size; }
};
template<size_t sz>
struct Derived: public Base
{
std::array<int, sz> data;
Derived():
Base(sz, &data[0])
{ }
};
int main()
{
Derived<5> d5;
d5.data[2] = 1234;
Base* b = &d5;
std::cout << b->up(2) << std::endl;
}
From your comment, it sounds like something like this might suffice:
#include <cstddef>
#include <array>
#include <algorithm>
template <typename T>
struct ArrayBase
{
typedef T type;
type & operator[](std::size_t i) { return buf[i]; }
type const & operator[](std::size_t i) const { return buf[i]; }
protected:
ArrayBase(type * p) : buf(p) { }
private:
type * buf;
};
template <typename T, std::size_t N>
struct Array : ArrayBase<T>
{
Array()
: ArrayBase<T>(a.data())
{
}
Array(Array const & rhs)
: ArrayBase<T>(a.data())
{
std::copy(rhs.a.begin(), rhs.a.end(), a.begin());
}
private:
std::array<T, N> a;
};
Usage:
Array<int, 5> a5;
ArrayBase<int> & b = a5;
b[2] = 11;
Array<int, 5> a52 = a5;
a52[2] = 13;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With