https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86480

            Bug ID: 86480
           Summary: [8 Regression] error: parameter packs not expanded
                    with '...' in a recursive variadic lambda
           Product: gcc
           Version: 8.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: gufideg at gmail dot com
  Target Milestone: ---

The following code compiler with Clang and GCC 7.3:

    #include <type_traits>
    #include <functional>
    #include <tuple>

    template<typename Tuple, typename =
std::make_index_sequence<std::tuple_size_v<Tuple>>>
    struct tuple_sequence_helper;

    template<typename T, typename I, I... S>
    struct tuple_sequence_helper<T, std::integer_sequence<I, S...>> {
        using type = std::tuple<std::integral_constant<I, S>...>;
    };

    template<auto N, typename F>
    constexpr auto apply_sequence(F function) -> decltype(auto) {
        return std::apply(function, typename tuple_sequence_helper<void,
std::make_integer_sequence<decltype(N), N>>::type{});
    }

    template<typename, typename>
    struct drop_last_helper;

    template<typename T, std::size_t... S>
    struct drop_last_helper<T, std::index_sequence<S...>> {
        using type = std::tuple<std::tuple_element_t<S, T>...>;
    };

    template<typename>
    struct drop_last;

    template<typename... Args>
    struct drop_last<std::tuple<Args...>> :
drop_last_helper<std::tuple<Args...>, std::make_index_sequence<sizeof...(Args)
- 1>> {};

    template<typename T>
    using drop_last_t = typename drop_last<T>::type;

    template<typename, typename Tup, typename, typename = void>
    struct dropping_invoke_result_helper {};

    template<typename F, typename... Args, typename T>
    struct dropping_invoke_result_helper<F, std::tuple<Args...>, T,
std::enable_if_t<std::is_invocable_v<F, Args...>>> {
        using type = std::invoke_result_t<F, Args...>;
    };

    template<typename F, typename H, typename... T, std::size_t... S>
    struct dropping_invoke_result_helper<F, std::tuple<H, T...>,
std::index_sequence<0, S...>, std::enable_if_t<!std::is_invocable_v<F, H,
T...>>> :
        dropping_invoke_result_helper<F, std::tuple<std::tuple_element_t<S - 1,
std::tuple<H, T...>>...>, std::make_index_sequence<sizeof...(S)>> {};


    template<typename F, typename... Args>
    using dropping_invoke_result = dropping_invoke_result_helper<F,
std::tuple<Args...>, std::index_sequence_for<Args...>>;

    template<typename F, typename... Args>
    using dropping_invoke_result_t = typename dropping_invoke_result<F,
Args...>::type;

    template<typename F, typename... Args>
    auto dropping_invoke(F&& f, Args&&... args) -> dropping_invoke_result_t<F,
Args...> {
        auto recurse = [](auto self) {
            return [self](auto&&... as) -> decltype(auto) { return self(self,
std::forward<decltype(as)>(as)...); };
        };

        auto drop = recurse([&f](auto self, auto&&... as) ->
dropping_invoke_result_t<F, Args...> {
            return apply_sequence<sizeof...(as) - 1>([&f, &as...,
&self](auto... s) -> decltype(auto) {
                auto pack =
std::forward_as_tuple(std::forward<decltype(as)>(as)...);

                if constexpr (std::is_invocable_v<F, std::tuple_element_t<s,
decltype(pack)>...>) {
                    return std::invoke(
                        std::forward<F>(f),
                        std::forward<std::tuple_element_t<s,
decltype(pack)>>(std::get<s>(std::move(pack)))...
                    );
                } else {
                    return self(self, std::forward<F>(f),
std::forward<std::tuple_element_t<s,
decltype(pack)>>(std::get<s>(std::move(pack)))...);
                }
            });
        });

        return drop(drop, std::forward<Args>(args)...);
    }

    int main() {
        dropping_invoke(
            [](auto a, int b){},
            42.f, 12, 23
        );
    }

I have not succeeded to reduce it more, sorry for the large repro.

Reply via email to