问题描述
如何获取参数包的前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::tuple
、std::integer_sequence
、 std::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_sequence
(make_consecutive_index_sequence
为 std::size_t
),以便我们可以为 head
、tail
和slice
以一致的方式。
编译时断言:
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"));