4

I have difficulties to understand the following. Why does this code compile

template <size_t N, size_t... N_i, size_t... M_i>
auto foo2(std::index_sequence<M_i...> = std::make_index_sequence<N>())
{

    constexpr size_t values[] = {N_i...};
    return A<values[M_i]...>();
}


template <size_t N,size_t... N_i>
auto foo()
{
    return foo2<N,N_i...>(std::make_index_sequence<N>());
}


int main()
{
 foo<2, 1,2,3>();
}

but this not (where I use the default argument of foo2):

template <size_t N, size_t... N_i, size_t... M_i>
auto foo2(std::index_sequence<M_i...> = std::make_index_sequence<N>())
{

    constexpr size_t values[] = {N_i...};
    return A<values[M_i]...>();
}


template <size_t N,size_t... N_i>
auto foo()
{
    return foo2<N,N_i...>();
}


int main()
{
 foo<2, 1,2,3>();
}

Many thanks in advance.

abraham_hilbert
  • 2,221
  • 1
  • 13
  • 30

1 Answers1

4

Given:

template <size_t N, size_t... N_i, size_t... M_i>
auto foo2(std::index_sequence<M_i...> = std::make_index_sequence<N>());

You can't explicitly specify M_i (because the sequence would just get swallowed up as part of N_i). If you specify an argument, then the compiler can use template argument deduction to work out what M_i is. If you don't specify an argument, then the compiler has no way to deduce what M_i is (and it needs to know that before it can start deciding you need a default argument, and what that argument is).

Assuming that this is a smaller part of a larger whole, then the fix is to write

template <size_t N, size_t... N_i, size_t... M_i>
auto foo2(std::index_sequence<M_i...>)
{

    constexpr size_t values[] = {N_i...};
    return A<values[M_i]...>();
}


template <size_t N,size_t... N_i>
auto foo2()
{
    return foo2<N,N_i...>(std::make_index_sequence<N>());
}

Then you can indeed write:

template <size_t N,size_t... N_i>
auto foo()
{
    return foo2<N,N_i...>();
}