0

Suppose I have the following function template:

int bar();

template <std::size_t... Is>
void foo()
{
    constexpr auto N = sizeof...(Is);
    int a[N] {/* magic here, like bar()... */};
}

I want to initialize the array a with N bar()s. The first solution I came up with is like the following:

int a[N] {(Is, bar())...};

But it results in some "expression result unused" warnings.

LIVE EXAMPLE

How can I get rid of these warnings if I don't want to turn off the -Wunused-value flag? Or is there any other way to write N bar()s? It is better that the solution works not only for bar(), but also for any expression that does not depend on Is.


Edit: the use of initializing an array is only an example. There are many other contexts that require such a sequence of expressions (for example, use for arguments of another template). So what I really want is how to generate such a sequence rather than to initialize the array.

xskxzr
  • 12,442
  • 12
  • 37
  • 77
  • When using C++ try and steer towards solutions that use containers like `std::vector` and away from those that use C-style arrays. – tadman Jun 15 '18 at 15:14
  • 2
    What about `((void)Is, bar())...`? An explicit cast to `void` expresses an explicit disinterest in a value. – François Andrieux Jun 15 '18 at 15:15
  • @tadman `vector` cannot be used at compile time. – NathanOliver Jun 15 '18 at 15:15
  • @FrançoisAndrieux OK, that's a nice answer. – xskxzr Jun 15 '18 at 15:16
  • @NathanOliver Does [this](https://stackoverflow.com/questions/8906545/how-to-initialize-a-vector-in-c) count? Having a variable length initialization is problematic, but that's the crux of this question and applies equally to both C array and C++ solutions. – tadman Jun 15 '18 at 15:17
  • Do you need `bar()` to run N times? Does it have any side-effects? – einpoklum Jun 15 '18 at 15:24
  • @tadman, just nitpicking: The alternative to these kind of C-style arrays is `std::array`, not `std::vector`. – andreee Jun 15 '18 at 15:28
  • @andreee There's a bunch of containers available and each has their various benefits and drawbacks. `std::vector` is a good default in most cases. `std::array` might be better here, but as this thing isn't actually used in this trivial demonstration code, it's hard to say what the best fit really is. – tadman Jun 15 '18 at 15:31
  • @einpoklum Yes, it may have side-effects. If it has no side-effect, does the problem get simplified? – xskxzr Jun 15 '18 at 15:34
  • @xskxzr If `bar` has side effects, be sure that the order of evaluation doesn't matter. Notably, `bar` better always return the same thing for the duration of the initialization of a given `a`. Order of evaluation for operands is unspecified in c++. – François Andrieux Jun 15 '18 at 15:38

2 Answers2

3

This solution requires two steps, but you could do something like initialize the array, then std::fill_n with values.

template <std::size_t... Is>
void foo()
{
    constexpr auto N = sizeof...(Is);
    int a[N];
    std::fill_n(a, N, bar());
}
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • 2
    Alternately `std::generate_n(a, N, bar)`, if the result of `bar` is expected to change, or isn't copyable – Caleth Jun 15 '18 at 15:24
  • @Caleth: You should really make that an answer, since it's distinctly better. – einpoklum Jun 15 '18 at 15:29
  • @Caleth If `bar` is expected to change then the original example is at best unspecified behavior for `N > 1`. Though it would be more in line with the original intention, for example if `bar` had side effects such as counting the number of calls to it or something where the order of execution doesn't matter. – François Andrieux Jun 15 '18 at 15:35
3

One possible way is to silent the warning locally, as casting to void:

int a[N] {(static_cast<void>(Is), bar())...};

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302