Unexpanded parameter pack in function signature

Viewed 371

Newer GCC introduced a new builtin __integer_pack to help it implement std::make_integer_sequence and friends. For Reasons(tm), I am unable to use this function, so I'm trying to reimplement it (and then use #define to replace the standard library usage)

It's used in the form __integer_pack(N)..., which expands its "return value". However I can't convince the type of my own templates to match this, with clang (10) erroring with:

error: pack expansion does not contain any unexpanded parameter packs

using make_integer_sequence = integer_sequence<_Tp, integer_pack(_Num)...>;

Is this even possible?

Here's what I've got so far:

#include <cstddef>


template <std::size_t...> struct index_sequence {};

template <std::size_t N, std::size_t... Is>
struct integer_pack : integer_pack<N - 1, N - 1, Is...> {};

template <std::size_t... Is>
struct integer_pack<0u, Is...> : index_sequence<Is...> { using type = index_sequence<Is...>; };


// Assume nothing below here can be changed.
#include <iostream>

/// Class template integer_sequence
template<typename _Tp, _Tp... _Idx>
struct integer_sequence
{
    typedef _Tp value_type;
    static constexpr size_t size() noexcept { return sizeof...(_Idx); }
};

// debugging aid
template<typename T, T... ints>
void print_sequence(integer_sequence<T, ints...> int_seq)
{
    std::cout << "The sequence of size " << int_seq.size() << ": ";
    ((std::cout << ints << ' '),...);
    std::cout << '\n';
}

template<typename _Tp, _Tp _Num>
using make_integer_sequence = integer_sequence<_Tp, integer_pack(_Num)...>;

int main()
{
    print_sequence(make_integer_sequence<int, 20>{});
}
1 Answers

No, this is not possible. __integer_pack is not a function, it is a placeholder that is expanded by the compiler into a parameter pack. This is not something you can replicate within the language.

You can look at how gcc implements replacing the call to __integer_pack with its expansion in gcc/cp/pt.c, starting at line 3750 currently. builtin_pack_fn_p() identifies calls to __integer_pack (the _p suffix means "predicate"), and expand_integer_pack performs the expansion.

You will need to write your own implementation (or copy an existing one) within the language.

Related