Andreas
Andreas

Reputation: 343

C++ initialize a std::array of aggregate types with values

I'm wondering how to intialize a N element std::array of a struct.

Example:

struct SomeStruct {
  uint32_t * const entry1;
  uint16_t * const entry2;
  uint16_t * const entry3;
};

Initialization is possible by:

static const std::array<SomeStruct , 2> arr
{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
// nullptr just for example, would be addresses of real variables in the project

But this is not exactly what I need because the following statement works as well without any warning or something else, and therefore leaves elements default initilized.

static const std::array<SomeStruct , 2> arr
{nullptr, nullptr, nullptr, nullptr};

What I need is a strong check of the compiler whether all elements are initialized, in a syntax something like that:

static const std::array<SomeStruct , 2> arr
{{nullptr, nullptr, nullptr}, {nullptr, nullptr, nullptr}};

Is it possible to force C++ to check that all elements of the aggragte type to be initialized?

Tank you!

Upvotes: 0

Views: 457

Answers (2)

aerkenemesis
aerkenemesis

Reputation: 672

You could use std::make_array and static_assert the resulting type. The std::make_array is however only a proposal but there is a reference implementation here.

namespace details {
  template<class> struct is_ref_wrapper : std::false_type {};
  template<class T> struct is_ref_wrapper<std::reference_wrapper<T>> : std::true_type {};

  template<class T>
  using not_ref_wrapper = std::experimental::negation<is_ref_wrapper<std::decay_t<T>>>;

  template <class D, class...> struct return_type_helper { using type = D; };
  template <class... Types>
  struct return_type_helper<void, Types...> : std::common_type<Types...> {
      static_assert(std::experimental::conjunction_v<not_ref_wrapper<Types>...>,
                    "Types cannot contain reference_wrappers when D is void");
  };

  template <class D, class... Types>
  using return_type = std::array<typename return_type_helper<D, Types...>::type,
                                 sizeof...(Types)>;
}

template < class D = void, class... Types>
constexpr details::return_type<D, Types...> make_array(Types&&... t) {
  return {std::forward<Types>(t)... };
}

Upvotes: 0

eerorika
eerorika

Reputation: 238301

But this is not exactly what I need because the following statement works as well without any warning or something else, and therefore leaves elements default initilized.

It does not leave elements default initialized. cppreference on aggregate initialization, emphasis mine:

If the number of initializer clauses is less than the number of members or initializer list is completely empty, the remaining members are value-initialized. If a member of a reference type is one of these remaining members, the program is ill-formed.

The exact wording changed in C++11, but not in a way that affects your case.

So, if you want to initialize all to nullptr, simply use

static const std::array<SomeStruct , 2> arr{};

If you wish for a warning when any element is not explicitly initialized, then you have no portable solution. There is no way for the compiler to know whether the value-initialization of the rest of the array was intentional or not.

A non-portable solution: GCC has a warning flag -Wmissing-field-initializers.

warning: missing initializer for member 'SomeStruct::entry2' [-Wmissing-field-initializers]

{nullptr, nullptr, nullptr, nullptr};
                                   ^

Upvotes: 3

Related Questions