Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialize all elements or std::array with the same constructor arguments

Tags:

c++

templates

I am wondering if it's possible to initialize a std::array of objects with an implicitly deleted default constructor, without knowing a priori the size of the array because it's a template argument and so having lost the possibility of using an initializer list. Code follows, it breaks with a "call to implicitly-deleted default constructor of std::array<A, 3UL>"

struct A {
  A (int b, int c) : mb(b), mc(c) { }
  int mb;
  int mc;
};

template <size_t NR_A>
struct B {
  B (int b, int c) : 
    // <- how to initialize mAs here?
  { }
  std::array<A, NR_A> mAs;
};

B<3> inst(1,1);

edit: I'd like to initialize all the A's of mAs to A{1,1}

like image 603
Alex Darsonik Avatar asked Mar 16 '18 10:03

Alex Darsonik


People also ask

Does std :: array default constructor?

std::array::array For elements of a class type this means that their default constructor is called. For elements of fundamental types, they are left uninitialized (unless the array object has static storage, in which case they are zero-initialized).

How do you pass an array to a constructor in C++?

In c++ , the name of the array is a pointer to the first element in the array. So when you do *state = *arr , you store the value at arr[0] in the variable state. Show activity on this post. The name of an array is the address of the first element in it.

Does std :: array initialize?

std::array contains a built-in array, which can be initialized via an initializer list, which is what the inner set is. The outer set is for aggregate initialization.


3 Answers

You may use delegating constructors and pack expansion

struct A {
    A(int b, int c) : b(b), c(c) { }
    A(const A&) = delete;
    A(A&&) = delete;
    int b;
    int c;
};

template <size_t N>
struct B {
  B (int b, int c) : B(b, c, std::make_index_sequence<N>{}) {}

  template<size_t... Is>
  B (int b, int c, std::index_sequence<Is...>) :
    arr{(Is, A{b, c})...}
  {}

  std::array<A, N> arr;
};

Live

Note if the move and copy constructors are deleted, this will only work after C++17.

like image 98
Passer By Avatar answered Nov 16 '22 05:11

Passer By


For both C++11 and C++14 (i.e.: pre-C++17) what you want can be achieved by means of template metaprogramming.

You could declare the following helper class template, array_maker<>, which has a static member function template, make_array, that calls itself recursively:

template<typename T, std::size_t N, std::size_t Idx = N>
struct array_maker {
    template<typename... Ts>
    static std::array<T, N> make_array(const T& v, Ts...tail) {
        return array_maker<T, N, Idx-1>::make_array(v, v, tail...);
    }
};

Then, specialize this class template for the case Idx equal to 1, i.e.: the base case of the recursion:

template<typename T, std::size_t N>
struct array_maker<T, N, 1> {
    template<typename... Ts>
    static std::array<T, N> make_array(const T& v, Ts... tail) {
        return std::array<T, N>{v, tail...};
    }
};

Finally, it can be used in the constructor of your template this way:

template <size_t NR_A>
struct B {
  B (int b, int c) : mAs{array_maker<A, NR_A>::make_array(A{b,c})}
  {}    
  std::array<A, NR_A> mAs;
};
like image 24
ネロク・ゴ Avatar answered Nov 16 '22 05:11

ネロク・ゴ


here's a solution I came up with (requires c++17)

template<typename T, std::size_t N, std::size_t index_t = N, typename... Ts>
constexpr auto make_array(T t, Ts... ts)
{
  if constexpr (index_t <= 1) {
    return std::array<T, N> {t, ts...};
  } else {
    return make_array<T, N, index_t - 1>(t, t, ts...);
  }
}

This is a modification of one of the previous solution that had an array maker struct. This does the same just in a more concise form.

It takes in a single item and keeps doubling down on that item until it reaches a depth of 1,then returns an array from the unfolding. I didn't realize that you a fold expression can be used even though no arguments are passed through it. Although I know this implicitly from things like printf.

like image 42
Manuel Meraz Avatar answered Nov 16 '22 05:11

Manuel Meraz