How to include different number of objects at compile time in the initializer list?

Viewed 90

I need to include a different number of objects depending on the provided 'define' and with different ctor parameters

inline static std::array<A::Output, NUM_OUTPUTS> s_Outputs =
{
#if NUM_OUTPUTS > 0
    A::Output{0}
#endif
#if NUM_OUTPUTS > 1
    , A::Output{1}
#endif
#if NUM_OUTPUTS > 2
    , A::Output{2}
#endif
};

Well depending on NUM_OUTPUTS respective number of the object should be created. Each object has an index, first is '0' and every next is '+1'.

Is there a way to do it more nicely? Probably macros to roll out in such declarations or anything else.

2 Answers

Using std::make_index_sequence and a variable template you can do.

#include <utility>  // std::integer_sequence

template <std::size_t... I>
constexpr auto makeArray(std::index_sequence<I...>)
{
   return std::array<A::Output, sizeof...(I)>{I...};
}
template<std::size_t NUM_OUTPUTS>
constexpr static std::array<A::Output, NUM_OUTPUTS> s_Outputs = makeArray(std::make_index_sequence<NUM_OUTPUTS>{});

Now you can

constexpr auto arr1 = s_Outputs<1>;  // 0
constexpr auto arr2 = s_Outputs<2>;  // 0 1
constexpr auto arr3 = s_Outputs<3>;  // 0 1 2

(See a Demo Online)

Note that, the above solution required compiler support.

You could define various templates and choose the appropriate specialization based on the preprocessor variable:

template<std::size_t I>
class outputs;

template<>
class outputs<1> {
    static std::array<A::Output,1> value = {{0}};
};

template<>
class outputs<2> {
    static std::array<A::Output,2> value = {{0}, {1}};
};

template<>
class outputs<3> {
    static std::array<A::Output,3> value = {{0}, {1}, {2}};
};

inline static auto s_Outputs = outputs<NUM_OUTPUTS>::value;

For a more generic variant you could use std::index_sequence in conjunction with a little helper function (C++17 code):

template<std::size_t... Ints>
decltype(auto) make_integer_array_helper(std::index_sequence<Ints...>) {
   return std::array { A::Output{Ints...} };
}

template<std::size_t N>
decltype(auto) make_integer_array() {
   return make_integer_array_helper(std::make_index_sequence<N>());
}

inline static auto s_Outputs = make_integer_array<NUM_OUTPUTS>();
Related