从参数包中排除前 n 个参数
Exclude first n arguments from parameter pack
我有一个函数foo
,它调用一个函数bar
,其中包含传递到foo
的可变参数模板中的类型子集。例如:
template <typename... T>
void foo() {
// ...
template <size_t start_idx, typename... T>
using param_pack = /*Parameter pack with T[start_idx]...T[N]*/
auto b = bar<param_pack<2, T...>>();
// ...
}
有没有办法提取"子参数包"。在上述情况下 如果是T = [int float char double]
,则param_pack<2, T...> = [char double]
[编辑]
我的目标是能够使用这样的东西来匹配事件处理程序。例如
struct ev {};
template <typename... T>
struct event : ev {
std::tuple<T...> data_;
event(T&&... d) : data_(std::make_tuple(std::forward<T>(d)...)) {}
};
template <typename... Functor>
struct handler {
std::tuple<Functor...> funcs_;
handler(Functor&&... f) : funcs_(std::make_tuple(std::forward<Functor>(f)...)) {}
void handle_message(ev* e) {
auto ptrs = std::make_tuple(
dynamic_cast<event<param_pack<1, typename function_traits<F>::args>>*>(e)...
);
match(ptrs);
}
};
在这里,function_traits::args
获取函数参数的参数包,并在检查dynamic_cast
是否成功并执行第一个成功的函数funcs_
对元组进行匹配迭代。我已经实现了这些。
处理程序类似于
[] (handler* self, <ARGS>) -> void {
// ...
}
我本质上是在试图摆脱self
论点。
为了简单起见,撇开它缺少对索引N
的检查这一事实,这里有一个基于函数声明(不需要定义(和 using 声明的可能解决方案:
template<std::size_t N, typename... T, std::size_t... I>
std::tuple<std::tuple_element_t<N+I, std::tuple<T...>>...>
sub(std::index_sequence<I...>);
template<std::size_t N, typename... T>
using subpack = decltype(sub<N, T...>(std::make_index_sequence<sizeof...(T) - N>{}));
这种方法的好处是,您不必引入围绕元组设计的新类型,然后以某种方式迭代地对其进行专用化。
它遵循一个使用上述代码的最小工作示例:
#include<functional>
#include<tuple>
#include<cstddef>
#include<type_traits>
template<std::size_t N, typename... T, std::size_t... I>
std::tuple<std::tuple_element_t<N+I, std::tuple<T...>>...>
sub(std::index_sequence<I...>);
template<std::size_t N, typename... T>
using subpack = decltype(sub<N, T...>(std::make_index_sequence<sizeof...(T) - N>{}));
int main() {
static_assert(std::is_same<subpack<2, int, float, char, double>, std::tuple<char, double>>::value, "!");
}
查看在 wandbox 上启动和运行的完整示例。
包含对索引N
检查的扩展版本如下所示:
template<std::size_t N, typename... T, std::size_t... I>
std::enable_if_t<(N < sizeof...(T)), std::tuple<std::tuple_element_t<N+I, std::tuple<T...>>...>>
sub(std::index_sequence<I...>);
这是您在第一个示例中看到的类型,一旦包裹在std::enable_if_t
中,仅此而已。同样,声明就足够了,不需要定义。
编辑
如果要使用自己的类模板而不是std::tuple
,则可以轻松修改代码以执行此操作:
#include<functional>
#include<tuple>
#include<cstddef>
#include<type_traits>
template<typename...>
struct bar {};
template<template<typename...> class C, std::size_t N, typename... T, std::size_t... I>
std::enable_if_t<(N < sizeof...(T)), C<std::tuple_element_t<N+I, std::tuple<T...>>...>>
sub(std::index_sequence<I...>);
template<template<typename...> class C, std::size_t N, typename... T>
using subpack = decltype(sub<C, N, T...>(std::make_index_sequence<sizeof...(T) - N>{}));
int main() {
static_assert(std::is_same<subpack<bar, 2, int, float, char, double>, bar<char, double>>::value, "!");
}
编辑
根据添加到问题中的代码,上面的解决方案仍然有效。您应该按如下方式定义event
类:
struct ev {};
template <typename>
struct event;
template <typename... T>
struct event<std::tuple<T...>>: ev {
// ...
};
这样,当您执行此操作时:
event<param_pack<1, typename function_traits<F>::args>>
您仍然可以从param_pack
中获得一个元组(这是我示例中使用声明的subpack
(,但它与event
的模板部分专用化匹配,并且参数包可供您使用T...
。
这是你能做的最好的事情,因为你不能将参数包放在 using 声明中。无论如何,它只是工作,所以它可能可以解决你的问题。
你可以做这样的事情:
template <std::size_t N, typename ... Ts> struct drop;
template <typename ... Ts>
struct drop<0, Ts...>
{
using type = std::tuple<Ts...>;
};
template <std::size_t N, typename T, typename ... Ts>
struct drop<N, T, Ts...>
{
using type = typename drop<N - 1, Ts...>;
};
// Specialization to avoid the ambiguity
template <typename T, typename... Ts>
struct drop<0, T, Ts...>
{
using type = std::tuple<T, Ts...>;
};
这是一个快速但不是特别可重用的解决方案。
template <typename Pack, std::size_t N, std::size_t... Is>
void invoke_bar_impl(std::index_sequence<Is...>) {
bar<std::tuple_element_t<N + Is, Pack>...>();
}
template <std::size_t N, typename... Ts>
void invoke_bar() {
auto indices = std::make_index_sequence<sizeof...(Ts) - N>();
invoke_bar_impl<std::tuple<Ts...>, N>(indices);
}
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- 从参数包中排除前 n 个参数
- 如果未设置编译符号,如何排除方法?如何传递可变数量的参数并在函数体中格式化它们
- 是否可以通过模板参数上的条件排除模板成员变量
- 编译时基于模板参数的条件包含/排除代码