0

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?

1
  • 1
    Pass array size by template argument? Note that, generally, a compiler needs to know how much storage to allocate for instances of C. Therefore, sizeof(C) must be the same and cannot depend on a constructor parameter. Commented May 11, 2020 at 18:14

3 Answers 3

5

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)

Sign up to request clarification or add additional context in comments.

Comments

2

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.

1 Comment

the parameter of std::array is std::size_t not int
1

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) {}
}

2 Comments

I do know the size at compile time. It's a constexpr, so it's known at compile-time.
@lomawa You know the size when the compiler calls the constructor, but the compiler needs to know it before when you declare the class. The compiler must know the class layout and the object size - and cannot know it just from looking at the class declaration that you provided. In fact your code will not compile if mysize is not known at the line std::array<int,mysize> data;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.