I have some custom objects, using a simplified example to show the problem I am having
#include <vector>
struct DataPoint {
int x = 0;
int y = 0;
}
// The goal of this object is to look like a vector but without the
// dynamic allocation (after initial initialization) hence why I am
// forcing a constructor like this.
class DataPoints {
public:
explicit DataPoints(size_t n) : points_(n) {};
private:
size_t current_size_ = 0;
std::vector<DataPoint> points_;
};
class DataLayers {
public:
// Here is where I have the problem, there is no default constructor for DataPoints,
// and need to initialize layers_ which is an array. I hope to eventually allow
// layers_ to be different sizes on initialization and so can't hard code an array
// initialization
DataLayers() :
// What I would like to do (this does not work) is something like this, and each
// array element in layers_ gets initialized to a size of 100000;
layers_(100000),
// Have also tried
layers(DataPoints(100000)) {
}
private:
std::array<DataPoints, 10> layers_;
}
I have got a temporary work around by setting a default argument in DataPoints
DataPoints(size_t n = 100000) // rest of code
I would prefer to move the initialization/sizing to Layers since Layers knows more about how many DataPoints it needs. Is this possible in C (using 14).
CodePudding user response:
You may be looking for something like this. With this, you can write
DataLayers() : layers_(make_std_array<DataPoints, 10>(std::size_t(100000))) {}
template <typename T, std::size_t size, typename U, std::size_t... Is>
std::array<T, size> make_std_array_helper(const U& init, std::index_sequence<Is...>) {
return {(Is, T{init}) ...};
}
template <typename T, std::size_t size, typename U>
std::array<T, size> make_std_array(const U& init) {
return make_std_array_helper<T, size>(init, std::make_index_sequence<size>{});
}
CodePudding user response:
std::array<DataPoints, 10> layers_;
You have ten DataPoints
here. Each one is a completely independent object, that has nothing to do with any of the nine instances of DataPoints
, that happen to live nearby in memory.
Each instance of a DataPoints
requires an explicit constructor. No matter which way you look, you have ten objects here. Each one needs to be constructed. There's no way to do it with just a single 100000
. That's only good enough to initialize one object, but you need ten of them.
As a result of that, you have no alternatives to constructing every one of these ten instances of DataPoints
, individually:
class DataLayers {
public:
DataLayers() :
layers_{{ DataPoints{100000},
DataPoints{100000},
DataPoints{100000},
DataPoints{100000},
DataPoints{100000},
DataPoints{100000},
DataPoints{100000},
DataPoints{100000},
DataPoints{100000},
DataPoints{100000}
}}
{
}
Welcome to C . The rules are very strict, and must be followed to the letter. If DataPoints
's constructor was not explicit
you can reduce the pain, a little bit. If explicit
gets removed, this can be reduced to:
layers_{{ {100000},
{100000},
{100000},
{100000},
{100000},
{100000},
{100000},
{100000},
{100000},
{100000}
}}
The reason for all these braces has to do with other rules of C , for which there are no alternatives or shortcuts:
One set of braces for constructing the
layers
object.A
std::array
is a container that contains a single member, the array object, and its aggregate initialization requires its own set of braces.Finally each value in the array gets constructed with its own pair of braces.