切片参数包参数



我想将参数包拆分为所有的第一个和最后一个参数,但C++要求参数包是函数声明中的最后一个,所以这不是有效的代码。

template<typename... Ts, typename Last>
void func( Ts... args, Last last ) {
cout << "{ ";
( (cout << args << ", "), ... ) << last << " }n";
}

现在,我可以用这样一个不那么好的代码:

template<typename T0, typename T1, typename Last>
pair< tuple<T0, T1>, tuple<Last> > slice( T0 t0, T1 t1, Last last ) {
return { make_tuple( t0, t1 ), make_tuple( last ) };
}
template<typename T0, typename T1, typename T2, typename Last>
pair< tuple<T0, T1, T2>, tuple<Last> > slice( T0 t0, T1 t1, T2 t2, Last last ) {
return { make_tuple( t0, t1, t2 ), make_tuple( last ) };
}
template<typename... Ts>
void func( Ts... ts ) {
auto f = [](auto last, auto... args) {
cout << "{ ";
( (cout << args << ", "), ... ) << last << " }n";
};
apply( f, tuple_cat( slice(ts...).second, slice(ts...).first ) );
}
int main() {
func( "Hello", 4, 5 );
func( "Hello", 4, 5.4, "Mars"s );
}

但是如何正确地制作slice()呢?

https://godbolt.org/z/qbbP1YM9T

您可以将其转换为元组,并对其进行处理。

void f(){}; // empty pack
template<typename ...Ts>
void f(Ts&&... ts) {
auto tuple = std::forward_as_tuple(std::forward<Ts>(ts)...);
constexpr auto size = sizeof...(Ts);
auto&& last = std::get<size-1>(tuple);

[&]<std::size_t ...I>(std::index_sequence<I...>){
((std::cout << std::get<I>(tuple) << " , "), ...);
}(std::make_index_sequence<size-1>());
std::cout << last << 'n';
}

但在这种情况下,更改顺序更简单(正如@HolyBlackCat所说(

template<typename T, typename ...Ts>
void f(T&& t, Ts&&... ts) {
std::cout << t;
((std::cout << " , " << ts),...);
std::cout << 'n';
}

这里有一个slice函数。

template<typename ...Ts>
auto slice_last(Ts&&... args){
auto tuple = std::forward_as_tuple(std::forward<Ts>(args)...);
constexpr auto size = sizeof...(Ts);
auto without_last = 
[&]<std::size_t ...I>(std::index_sequence<I...>){
return std::forward_as_tuple(std::get<I>(std::move(tuple))...);
}(std::make_index_sequence<size-1>());
using last_type = std::tuple_element_t<size-1,decltype(tuple)>; 
return std::pair<decltype(without_last),last_type>(
std::move(without_last),
std::get<size-1>(std::move(tuple))
);
}
// use
template<typename... Ts>
void f(Ts&&... ts) {
auto [pack,last] = slice_last(std::forward<Ts>(ts)...);

cout << "{ ";
std::apply(
[](auto&&...ts){( (std::cout<<ts<<" ,"), ... );}
,pack
);
std::cout << last << " }n";
}

另一个选项是使用好的旧递归

template<typename T>
void f_impl(T&& last){
std::cout << last << " }n";
}
template<typename T, typename... Ts>
requires (sizeof...(Ts)!=0)
void f_impl(T t, Ts&&... ts) {
std::cout << t << ", ";
f_impl(std::forward<Ts>(ts)...);
}
template<typename... Ts>
void f(Ts&&... ts) {
std::cout << "{ ";
f_impl(std::forward<Ts>(ts)...);
}

这里是args_filter_apply()的一个相对简单的实现,它使用运行时过滤的参数包调用lambda。它还不是最佳的,但你可能会想到:

#include <iostream>
template<typename Filter, typename Funct>
auto args_filter_apply(Filter filter, Funct funct)
{
return funct();
}
template<typename Filter, typename Funct, typename Arg, typename... Args>
auto args_filter_apply(Filter&& filter, Funct&& funct, Arg& arg, Args&... args)
{
if (filter(arg)) {
return args_filter_apply(std::forward<Filter>(filter), [&](auto... args1) {
return std::forward<Funct>(funct)(arg, args1...);
}, args...);
}
return args_filter_apply(std::forward<Filter>(filter), std::forward<Funct>(funct), args...);
}

template<typename... Ts>
void func(Ts... args) {
std::cout << "{ ";
int i = 0;
args_filter_apply([&](auto arg) {
return ++i != sizeof...(args);
}, [](auto... myArgs) {
( (std::cout << myArgs << ", "), ... );
}, args...);
i = 0;
args_filter_apply([&](auto arg) {
return ++i == sizeof...(args);
}, [](auto... last) {
( (std::cout << last), ...);
std::cout << " }n";
}, args...);
}
int main()
{
func("Hello", 4, 5);
func("Hello", 4, 5.4, "Mars");
}

如果您首先将参数打包到一个序列中,那么很容易创建所需的任何切片。由于该标准没有提供专用设施,元组通常用于该目的。

这就是工作流程:

  1. 将参数作为元组转发
  2. 创建一个实现;切片";(此处除最后一个元素外的所有元素(使用索引序列进行访问
  3. 随意使用最后一个元素

这样的实现如下所示:

template <std::size_t... Is, class Tuple>
void func_impl(std::index_sequence<Is...>, Tuple&& t)
{
cout << "{ ";
( (cout << std::get<Is>(t) << ", "), ... ) 
<< std::get<std::tuple_size_v<Tuple> - 1>(t) 
<< " }n";
}
template<typename... Ts>
void func(Ts&&... args)
{
func_impl(
std::make_index_sequence<sizeof...(Ts) - 1>{}, 
std::forward_as_tuple(std::forward<Ts>(args)...));
}

演示

最新更新