0

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).

3
  • Well, can you explain where do you expect the parameter to the constructor to each instance of your layers_ DataPoints instance to come from? It has to come from somewhere. Commented Jan 15, 2023 at 22:24
  • 1
    "hope to eventually allow layers to be different sizes on initialization and so can't hard code an array initialization_": So you are going to make layers_ a std::vector instead of a std::array anyway, and then there won't be any issue. A std::vector can always be default-constructed. Commented Jan 15, 2023 at 22:27
  • @SamVarshavchik in this example DataLayers knows it needs 100000 elements. However in other parts of my code I use different sizes of DataPoints DataPoints(250) (for example) Commented Jan 15, 2023 at 22:28

2 Answers 2

1

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

Demo

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

Comments

0
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.

Comments

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.