lomawa
lomawa

Reputation: 3

C++ how to instantiate std::array inside a class constructor?

I want to have a big container (specifically a std::array) the size of which I know at compile time but which I can specify from the constructor.

I have been able to do the first part: i.e. a std::array which a size specified at compile time. Schematically:

// hpp
constexpr int my_size = 100;
class C
{
    std::array<int, my_size> data;
}
// main
c = C()

Now I would like to do the same thing, but with the std::array passed into the class constructor, possibly as an constexpr:

// hpp
class C
{
    std::array<int, mysize> data;
    C(constexpr int mysize);
}
// cpp
C::C(constexpr int mysize)
{
    data = std::array<int, mysize>
}
// main
constexpr int mysize = 100;
c = C(mysize);

Obviously this is wrong because mysize is passed in the constructor, but mysize is also part of the type which has to be known at the point of declaration.

So how do I do this?

Upvotes: 0

Views: 3382

Answers (3)

Bitwize
Bitwize

Reputation: 11220

Changing the extent (size) of std::array would change the size of the object containing it -- since the array elements are stored contiguously in the object rather than indirectly (e.g. via pointer).

A class' type must be "complete" in order for a constructor to be called -- and for a class to be "complete", it must be fully defined (and thus, a size must already be known). So effectively, passing it in via the constructor is not possible -- even if the value is a true constant expression.

The only way to accomplish what you are trying to do using std::array is to make the class a template on the size of the array. Templates allow the compiler to generate different classes based on the template argument inputs, so each instantiation can have a different size:

template <std::size_t N>
class C {
    ...
    std::array<int, N> data;
};

Note that in doing this, your definition for all associated functionality will likely be stuck in a header now -- since the entire definition must be visible for an instantiation to work correctly (which generally constrains them to headers). Additionally, templates can cause code-bloat by duplicating generated code for each instantiation; so this is something to consider if you anticipate a lot of instantiations of this template.


If you want to ever use this type based on runtime inputs, it would likely be simpler to use std::vector instead.


class C {
    C(int mysize) : data{mysize}{}
    std::vector<int> data;
};

However, the elements inside std::vector will not be stored directly in C, but rather will be indirectly stored in allocated memory (likely on the heap)

Upvotes: 5

Werner Henze
Werner Henze

Reputation: 16726

std::array is for arrays with a size that is known at compile time. In your case you need an array with a size that is set at runtime. You need std::vector.

class C
{
    std::vector<int> data;
    C(constexpr size_t mysize) : data(mysize) {}
}

Upvotes: 1

kmdreko
kmdreko

Reputation: 59882

C would need to be made a template class based on an int and constructed accordingly:

template <int my_size>
class C
{
    std::array<int, my_size> data;
}

auto c = C<100>();

You cannot specify a template parameter (N in std::array<T, N>) with a function parameter. constexpr doesn't help here.

Upvotes: 2

Related Questions