I’m trying to find the best way to pass a compile-time list of values to a utility function, as an exercise based on a real use case. This list will be subjected to some series of operations and the resulting value will be used in another operation in runtime. Below are some solutions I found, simplified to MWEs.

Of course, the operations are much more complex in the real use case, hence the need for these utility functions.

## Solution 1: Parameter pack

```
template <int number>
constexpr int sum() {
return number;
}
template <int number, int next, int... rest>
constexpr int sum() {
return number + sum<next, rest...>();
}
//API:
template <int... numbers>
inline void add(int& target) {
target += sum<numbers...>();
}
...
int number = 0;
add<1, 2, 3, 4, 5>(number);
```

**Pros**:

- Clean API
- Needs only c++14

**Cons**:

- Clunky implementation with recursion, painful to design and read when operations are complex

## Solution 2: `std::array`

```
template <size_t N, std::array<int, N> numbers>
constexpr int sum() {
int ret = 0;
for (int number : numbers)
ret += number;
return ret;
}
//API:
template <size_t N, std::array<int, N> numbers>
inline void add(int& target) {
target += sum<N, numbers>();
}
...
int number = 0;
add<5, std::array{1, 2, 3, 4, 5}>(number);
```

**Pros**:

- Clean and readable implementation, easy to design no matter the complexity of operations

**Cons**:

- Super clunky API, size of list must be specified separately
- Needs c++20 to be able to pass inline
`std::array`

as non-type template parameter

## Solution 3: `std::array`

wrapper

```
template <size_t N>
struct IntArray {
constexpr IntArray(std::array<int, N> arr_) : arr(arr_) {}
const std::array<int, N> arr;
};
template <IntArray numbers>
constexpr int sum() {
int ret = 0;
for (int number : numbers.arr)
ret += number;
return ret;
}
//API:
template <IntArray numbers>
inline void add(int& target) {
target += sum<numbers>();
}
...
int target = 0;
add<IntArray<5>({1, 2, 3, 4, 5})>(target);
```

**Pros**:

- Clean and readable implementation, easy to design no matter the complexity of operations

**Cons**:

- (Arguably) less but still clunky API, size of list must be specified separately
- Needs c++20 to be able to pass inline
`IntArray`

as non-type template parameter, and also to be able to omit the`IntArray`

template parameter value in at least the function definitions

## Solution 4: `std::initializer_list`

```
template <std::initializer_list<int> numbers>
constexpr int sum() {
int ret = 0;
for (int number : numbers)
ret += number;
return ret;
}
template <std::initializer_list<int> numbers>
inline void add(int& target) {
target += sum<numbers>();
}
...
int target = 0;
add<{1, 2, 3, 4, 5}>(target);
```

**Pros**:

- Clean and readable implementation, easy to design no matter the complexity of operations
- Clean, usable and readable API

**Cons**:

- Doesn’t actually compile (g++ 10.3.0 with
`gnu++2a`

):`‘std::initializer_list<int>’ is not a valid type for a template non-type parameter because it is not structural`

I have no idea what "not structural" means to be very honest. I’m actually surprised and disappointed by the fact that this approach doesn’t work, given that `std::initializer_list`

is apparently fully `constexpr`

and `std::array`

works in the same situation. There seems to be a bug in the standard about the literalness of `std::initializer_list`

though: https://stackoverflow.com/a/28115954/1525238 In any case, I do see this as a missed opportunity for some really cool compile-time wizardry.

## The question:

Can you suggest any way to improve the solutions above in any way possible, or suggest other solutions?

Source: Windows Questions C++