C ++:获取参数包的开头和结尾

问题描述

如何获取参数包的前n个元素?还是一般来说[n,n + 1,...,m)中的最后n个元素或元素切片?例如:

df = df.assign(course_code = lambda x: x['course_code'].apply(lambda s: s.split(' - ')[0]))

这可以通过结合std :: tuple,std :: integer_sequence和std :: get来实现,但我想知道是否还有更简单的方法

解决方法


template <typename T,typename... J>
T GetFirstPack(T t,J... j) {
    return t;
}

template <typename T>
T GetLastPack(T t) {
    return t;
}
template <typename T,typename...J>
auto GetLastPack(T t,J... j) {
    return GetLastPack(j...);
}

template <typename... T>
void TestFunction(T... t) {
    std::cout << GetFirstPack(t...) << std::endl;
    std::cout << GetLastPack(t...) << std::endl;
}

int main() {
    // your code goes here
    TestFunction("first","second",10);
    return 0;
}

首先要考虑的是琐碎的事,最后要考虑拆箱规则会比较棘手。您可以使用rhr使其更有效率。

,

有一种方法可以为 std::integer_sequence 创建一个新的工厂别名,通过使用 std::tuplestd::integer_sequencestd::get

假设这个别名的名称是 make_consecutive_integer_sequence

namespace detail {
  template <typename T,auto Start,auto Step,T... Is>
  constexpr auto make_cons_helper_impl_(std::integer_sequence<T,Is...>) {
    auto eval_ = [](const T& I) consteval -> T { return Start + Step * I; };
    return std::integer_sequence<T,eval_(Is)...>{};
  }

  template <typename T,auto Count,auto Step>
  constexpr auto make_cons_impl_() {
    return make_cons_helper_impl_<T,Start,Step>(std::make_integer_sequence<T,Count>{});
  }
} // namespace detail

template <std::integral T,auto Step = 1>
using make_consecutive_integer_sequence = decltype(
  detail::make_cons_impl_<T,Count,Step>()
);

template <auto Start,auto Step = 1>
using make_consecutive_index_sequence = make_consecutive_integer_sequence<std::size_t,Step>;

然后,应用 make_consecutive_integer_sequence 的用法:

template <std::size_t N>
using make_first_n_index_sequence = make_consecutive_index_sequence<0,N>;

template <std::size_t N,std::size_t S>
using make_last_n_index_sequence = make_consecutive_index_sequence<S - N,N>;

template <std::size_t B,std::size_t E>
using make_slice_index_sequence = make_consecutive_index_sequence<B,E - B>;

我们仍然需要将参数包包装std::tuple 中。

template <typename... Ts,std::size_t... Is>
constexpr auto get_subpack_by_seq(std::index_sequence<Is...>,Ts&&... args) {
    return std::make_tuple(std::get<Is>(std::forward_as_tuple(args...))...);
}

template <std::size_t N,typename... Ts>
requires (N <= sizeof...(Ts))
constexpr auto head(Ts&&... args) {
    return get_subpack_by_seq(
        make_first_n_index_sequence<N>{},std::forward<Ts>(args)...
    );
}

template <std::size_t N,typename... Ts>
requires (N <= sizeof...(Ts))
constexpr auto tail(Ts&&... args) {
    return get_subpack_by_seq(
        make_last_n_index_sequence<N,sizeof...(Ts)>{},std::forward<Ts>(args)...
    );
}

template <std::size_t B,std::size_t E,typename... Ts>
requires (B < E && B <= sizeof...(Ts) && E <= sizeof...(Ts))
constexpr auto slice(Ts&&... args) {
    return get_subpack_by_seq(
        make_slice_index_sequence<B,E>{},std::forward<Ts>(args)...
    );
}

这里的目标是概括 make_consecutive_integer_sequencemake_consecutive_index_sequencestd::size_t),以便我们可以为 headtailslice 以一致的方式。

编译时断言:

static_assert(head<3>(1,2.0f,"three",'4') == std::make_tuple(1,"three"));
static_assert(tail<2>(1,'4') == std::make_tuple("three",'4'));
static_assert(slice<1,3>(1,'4') == std::make_tuple(2.0f,"three"));