2

我有一个函数foo,它调用函数bar,并传入foo的可变参数模板的子类型。例如:排除参数包中的前n个参数

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说法。

+0

一个相关的问题:https://stackoverflow.com/questions/8569567/get-part-of-stdtuple – keith

+0

抱歉...我的坏...制作编辑现在 – subzero

回答

3

抛开它缺乏对简单的指数N检查的事实,这里是一个基于函数声明(无需定义)和一个可能的解决方案使用声明:

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...

这是最好的,你可以做,因为你不能把一个参数包放入使用声明。无论如何,它只是工作,所以可能它可以解决你的问题。

+0

这个类型是'std :: tuple '有没有办法直接获取包,即'T ...' – subzero

+0

@subzero你不能在一个using声明中放入一个包,你所能做的就是将你想要填充的类型与其他数据一起传递,并将它取回,而不是一个元组,它可以为你工作吗?你想如何使用它? – skypjack

+0

@subzero我添加了另一个例子来说明如何使用你自己的类模板,让我知道它是否适用于你 – skypjack

2

你可以这样做:

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...>; 
}; 
+0

我试图实现类似的想法,但由于编译器不能选择'N = 0'的特殊化这一事实而陷入困境。你可以看一下:https://wandbox.org/permlink/u3QOECdxokexLgyG –

+0

@EdgarRokyan:确实需要额外的专业化。 [修正版](https://wandbox.org/permlink/K0Bb3MwjwTtJFU8x)。 – Jarod42

+0

完美,谢谢!虽然它现在看起来有点尴尬:( –

0

这是一个快速但不是特别可重用的解决方案。

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); 
}