Skip to content

Instantly share code, notes, and snippets.

@dgodfrey206
Created December 27, 2025 19:51
Show Gist options
  • Select an option

  • Save dgodfrey206/260ef8f7befcd74f23b023366e760b35 to your computer and use it in GitHub Desktop.

Select an option

Save dgodfrey206/260ef8f7befcd74f23b023366e760b35 to your computer and use it in GitHub Desktop.
Split argument list
#include <utility>
#include <string>
#include <tuple>
#include <print>
#include <functional>
#include <concepts>
#include <memory>
#include <iostream>
namespace detail {
template<std::size_t I>
using make_sequence = std::make_index_sequence<I>;
template<std::size_t... Is>
using index = std::index_sequence<Is...>;
template<int I, class Sequence>
struct drop_before;
template<std::size_t... Is>
struct drop_before<0, index<Is...>> {
using type = index<Is...>;
};
template<int Idx>
requires(Idx != 0)
struct drop_before<Idx, index<>> {
using type = index<>;
};
template<int Idx, std::size_t I, std::size_t... Is>
requires(Idx != 0)
struct drop_before<Idx, index<I, Is...>> {
using type = typename drop_before<Idx-1, index<Is...>>::type;
};
// drop_after
template<int I, class Seq1, class Seq2>
struct drop_after;
template<std::size_t... Is, std::size_t U, std::size_t... Us>
struct drop_after<0, index<Is...>, index<U, Us...>> {
using type = index<Is..., U>;
};
template<int Idx, std::size_t... Is>
requires(Idx != 0)
struct drop_after<Idx, index<Is...>, index<>> {
using type = index<Is...>;
};
template<int Idx, std::size_t... Is, std::size_t J, std::size_t... Js>
requires(Idx != 0)
struct drop_after<Idx, index<Is...>, index<J, Js...>> {
using type = typename drop_after<Idx-1, index<Is..., J>, index<Js...>>::type;
};
template<int I, class Seq>
using drop_before_t=typename drop_before<I,Seq>::type;
template<int I, class Seq1, class Seq2>
using drop_after_t=typename drop_after<I,Seq1,Seq2>::type;
template<class F, class Tuple>
decltype(auto) indexes_of( F&& f, Tuple&& tup ) {
return std::invoke(std::forward<F>(f),
detail::make_sequence<std::tuple_size_v<std::decay_t<Tuple>>>{});
}
template<int I, class F, class Tuple>
decltype(auto) split( F&& f, Tuple&& tuple ) {
return indexes_of([f=std::forward<F>(f)]<std::size_t... Is>(detail::index<Is...>) {
using S=detail::index<Is...>;
using empty=detail::index<>;
return std::invoke(decltype(f)(f), detail::drop_after_t<I-1,detail::index<>,S>{}, detail::drop_before_t<I,S>{});
}, std::forward<Tuple>(tuple));
}
}
template<typename Parent>
struct C : public Parent {
struct Base {};
template<class... Ts>
struct inner : Base {
inner(Ts... ts, std::size_t size)
: data(size, 'X') { std::println("size_t"); }
inner(Ts... ts, std::string data)
: data(std::move(data)) { std::println("string"); }
std::string data;
};
template<int I, class Tuple>
requires(I>0)
decltype(auto) split( Tuple&& tup ) {
return detail::split<I>([&]<std::size_t... Is, std::size_t... Us>(detail::index<Is...>, detail::index<Us...>) {
return std::make_unique<inner<
decltype(std::get<Is>(tup))...
>>(std::get<Is>(tup)..., std::get<Us>(tup)...);
}, std::forward<Tuple>(tup));
}
template<int I, class Tuple>
requires(I<0)
decltype(auto) split( Tuple&& tup ) {
using Td=std::decay_t<Tuple>;
static constexpr auto N=std::tuple_size_v<Td>;
return split<N-(-I)-1>(std::forward<Tuple>(tup));
}
template<typename... ParentArgs>
C(ParentArgs&&... args)
: C(std::forward_as_tuple(std::forward<ParentArgs>(args)...)) {}
private:
template<class Tuple>
requires (!std::same_as<std::decay_t<Tuple>, C>)
C(Tuple&& tuple)
: m_inner(split<std::tuple_size_v<Tuple>-1>(std::forward<Tuple>(tuple))) {}
std::unique_ptr<Base> m_inner;
};
struct D {
int a;
int b;
};
template<class>
struct Z;
template<class... Ts>
void foo() {
C<D>::inner<Ts...> p(Ts{}..., "hi");
}
int main() {
using namespace std::literals;
using namespace detail;
auto test = C<D>(1, 3, "Hi"s);
auto test2 = C<D>(1, 3, 10uz);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment