gpt4 book ai didi

c++ - 从参数包中排除前 n 个参数

转载 作者:太空狗 更新时间:2023-10-29 20:21:12 24 4
gpt4 key购买 nike

我有一个函数 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获取函数参数的参数包并匹配迭代元组 funcs_检查是否 dynamic_cast成功并执行第一个成功的功能。我已经实现了这些。

处理程序是这样的

[] (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 using 声明),但它匹配 event< 的模板部分特化 和参数包作为 T... 供您使用。

这是你能做的最好的,因为你不能把参数包放在 using 声明中。无论如何它都能正常工作,所以它可能可以解决您的问题。

关于c++ - 从参数包中排除前 n 个参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45172034/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com