切片参数包参数
Slice parameter pack parameters
我想将参数包拆分为所有的第一个和最后一个参数,但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");
}
如果您首先将参数打包到一个序列中,那么很容易创建所需的任何切片。由于该标准没有提供专用设施,元组通常用于该目的。
这就是工作流程:
- 将参数作为元组转发
- 创建一个实现;切片";(此处除最后一个元素外的所有元素(使用索引序列进行访问
- 随意使用最后一个元素
这样的实现如下所示:
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)...));
}
演示
相关文章:
- 如何反转整数参数包
- 如何将enable-if与模板参数和参数包一起使用
- 模板元编程:如何将参数包组合成新的参数包
- C ++:在构造函数中使用参数包?
- 如何使我的 sizeof sum 结构与空参数包一起工作
- 双模板参数包
- 参数包构造函数在类模板中隐藏用户定义的转换
- 嵌套参数包扩展失败
- 参数包中的筛选器类型
- 参数和参数包的类型推导
- 为模板参数包添加别名
- enable_if中参数包的大小问题
- 如何使特征接受参数包?
- 参数包内 noexcept 说明符
- 获取可变参数模板参数包的相关类型
- C++17 有效地将参数包参数与 std::array 元素相乘
- 使用参数包参数初始化"std::array"
- 您如何使用参数包参数键入功能指针类型
- 参数包参数消耗
- 以最小的开销删除多余的参数包参数