7

I have the following (not compilable) code:

template< size_t N >
void foo( std::array<int, N> )
{
  // Code, where "N" is used.
}

int main()
{
  foo( { 1,2 } );
}

Here, I want to pass an arbitrary number of ints to a function foo -- for convenience, I will use the std::initializer_list notation. I tried to use an std::array to aggregate the ints (as shown in the code above), however, the compiler can not deduce the array size since the ints are passed as an std::initializer_list.

Using an std::initializer_list instead of an std::array also does not solve the problem since (in contrast to std::array) the size of the std::initializer_list is not captured as template argument.

Does anyone know which data structure can be used so that the ints can be passed by using the std::initializer_list notation and without passing the template argument N of foo explicitly?

Many thanks in advance

abraham_hilbert
  • 2,221
  • 1
  • 13
  • 30

2 Answers2

10

Thanks to core issue 1591, you can use

template <std::size_t N>
void foo( int const (&arr)[N] )
{
  // Code, where "N" is used.
}

foo({1, 2, 3});
Columbo
  • 60,038
  • 8
  • 155
  • 203
  • Thank you very much -- the solution works! Can you please help me to understand what `int const (&arr)[N]` is: an array? Moreover, using `int (&arr)[N]` without `const` does not work -- can you please help me to understand why? – abraham_hilbert Oct 25 '16 at 14:07
  • @abraham_hilbert 1) `int const (&arr)[N]` is a const reference to an array. 2) Are you aware that temporaries can be bound to const references, but not non-const references? Well, we're creating an array temporary and bind it to the reference, which is not permitted for non-const references. – Columbo Oct 25 '16 at 14:10
  • I see, thank you. One problem remains: the case of an empty initializer list should also be possible (i.e. `N==0`) which currently causes a compiler error. Do you see any solution? – abraham_hilbert Oct 25 '16 at 14:24
  • 1
    @abraham_hilbert What about adding `void foo (int) {/*code for N=0*/}` – Columbo Oct 25 '16 at 14:25
  • If there is no simple implementation for using an empty array (i.e., `{}`), I will use `void foo ()` -- thank you very much for the great tips. – abraham_hilbert Oct 25 '16 at 14:36
  • Is there anything equivalent for templated classes and their constructor (e.g. `Klass k({1,2,3})` would specialize template Klass) – Osman-pasha Mar 08 '21 at 12:48
  • 1
    @Osman-pasha [Are you looking for deduction guides](https://wandbox.org/permlink/XBe8ExpKRBSYFEuh)? – Columbo Mar 13 '21 at 13:24
  • @Columbo yes, thank you. I did not even know these things exist. – Osman-pasha Mar 24 '21 at 14:59
3

If using an initializer list is not a must, you can use variadic template parameter packs:

template<size_t S>
void foo_impl(array<int, S> const&)
{
    cout << __PRETTY_FUNCTION__ << endl;
}

template<typename... Vals>
auto foo(Vals&&... vals) {
    foo_impl<sizeof...(vals)>({ std::forward<Vals>(vals)... });
}

you'd call it as follows:

foo(1,2,3,4,5);

This defers common type checks until the initialization point of std::array (unless you add some admittedly ugly asserts), so you probably should prefer Columbo's answer.

krzaq
  • 16,240
  • 4
  • 46
  • 61