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