As an exercise, I would like to construct a vector containing std::array<unsigned char, N>
objects (where N
varies).
My attempt was to construct a base class GenericArray
from which a MyArray<N>
will derive, such that the container will actually be: std::vector<GenericArray*>
. However, since the actual array variable must reside in the derived class, I do not see a way to make use of this data from the std:vector<GenericArray*>
itself.
Here is my full attempt, which obviously produces: error: ‘class GenericArray’ has no member named ‘data’
#include <array>
#include <cassert>
#include <iostream>
#include <vector>
template<std::size_t N>
using arr_t = std::array<unsigned char, N>;
class GenericArray
{
public:
~GenericArray() = default;
};
template<std::size_t N>
class MyArray : public GenericArray
{
public:
arr_t<N> data;
MyArray(const arr_t<N>& data)
{
this->data = data;
}
};
int main(void)
{
std::vector<GenericArray*> vs;
vs.emplace_back(new MyArray<2>({ 'a', 'b' }));
vs.emplace_back(new MyArray<4>({ 'A', 'B', 'C', 'D' }));
assert(vs.size() == 2);
for (const auto& x : vs[0]->data)
{
std::cout << x << "\n";
}
return 0;
}
CodePudding user response:
You seem to be mixing two concepts. I recommend the version in eerorika's answer but if you really want base class pointers in your container, here's one way:
#include <array>
#include <iostream>
#include <vector>
#include <memory>
class GenericArray {
public:
using value_type = unsigned char;
using iterator = value_type*;
template<std::size_t N>
using arr_t = std::array<value_type, N>;
virtual ~GenericArray() = default; // must be virtual to call the derived dtor
virtual iterator begin() = 0; // used for iterating in the derived class
virtual iterator end() = 0;
// add `const` versions too as needed
};
template<std::size_t N>
class MyArray : public GenericArray {
public:
arr_t<N> data;
MyArray(const arr_t<N>& data) : data(data) {}
iterator begin() override { return data.data(); } // overridden
iterator end() override { return data.data() data.size(); } // -"-
};
int main() { // no need for main(void)
std::vector<std::unique_ptr<GenericArray>> vs;
vs.emplace_back(new MyArray<2>({ 'a', 'b' }));
vs.emplace_back(new MyArray<4>({ 'A', 'B', 'C', 'D' }));
// loop over the elements:
for(auto& ptr : vs) {
for(auto& x : *ptr) std::cout << x << ' ';
std::cout << '\n';
}
}```
CodePudding user response:
I would like to construct a vector containing std::array<unsigned char, N> objects (where N varies).
You cannot. Vectors, like all standard containers are homogeneous. They consist of a single element type. std::array<unsigned char, N>
and std::array<unsigned char, M>
are different types - given that N != M, and thus they cannot be stored in a homogeneous container.
You can use std::vector<std::vector<unsigned char>>
instead.
CodePudding user response:
I don't think it is possible. Let's say you make a class which contains a secvence of std::array<char,N>
s with a get
method. what should be the size of the returned result. The compiler must know the memory-size of all, variables for compiling, but it doesn't know the size of auto p=vct.get(i);
If get returns a pointer than size size of auto p=*vct.get(i);
is undefined.
The closest you can get is returning void*
and casting it to array<char,N>*
but N must be known compile-time