2011-11-06 26 views
3

如何(或有可能)用數字序列解壓參數包?例如,如何使用數字序列解包可變參數模板參數?

template <typename C, typename... T> 
C* init_from_tuple(bp::tuple tpl) 
{ 
    return new C{bp::extract<T>("magic"(tpl))...}; // <-- 
} 

其中<--線應擴大到

return new C{bp::extract<T0>(tpl[0]), 
       bp::extract<T1>(tpl[1]), 
       ..... 
       bp::extract<Tn>(tpl[n])}; 

n == sizeof...(T) - 1哪裏。

目的是爲Boost.Python創建一個__init__函數,它接受一個帶有預定義類型的元組。

回答

3

實際上,解包操作可以一次定位兩個不同的參數包(我認爲它們需要的長度相等)。在這裏,我們想要一組類型和一組數字。

一種近乎:

template <typename C, typename... T, size_t... N> 
C* init_from_tuple_impl(bp::tuple tpl) { 
    return new C{ bp::extract<T>(tpl[N])... }; 
} 

我們 「只是」 需要生成指數的包:

template <size_t... N> struct Collection {}; 

template <typename C> struct ExtendCollection; 

template <size_t... N> 
struct ExtendCollection< Collection<N...> > { 
    typedef Collection<N..., sizeof...(N)> type; 
}; 

template <typename... T> 
struct GenerateCollection; 

template <> 
struct GenerateCollection<> { typedef Collection<> type; }; 

template <typename T0, typename... T> 
struct GenerateCollection<T0, T...> { 
    typedef typename ExtendCollection< 
    typename GenerateCollection<T...>::type 
    >::type type; 
}; 

,然後使用它:

template <typename C, typename... T, size_t... N> 
C* init_from_tuple_impl(bp::tuple tpl, Collection<N...>) { 
    return new C { bp::extract<T>(tpl[N])... }; 
} 

template <typename C, typename... T> 
C* init_from_tuple(bp::tuple tpl) { 
    typename GenerateCollection<T...>::type collection; 
    return init_from_tuple_impl<C, T...>(tpl, collection); 
} 

在行動,在Ideone

我們可以通過在init_from_tuple_impl實施(除去new爲例)製作一個 「錯誤」 見證的正確性:

template <typename C, typename... T, size_t... N> 
C* init_from_tuple_impl(bp::tuple tpl, Collection<N...>) { 
    return C { bp::extract<T>(tpl[N])... }; 
} 

在行動,在Ideone

prog.cpp: In function 'C* init_from_tuple_impl(bp::tuple, Collection<N ...>) 
[with 
    C = bp::Object, 
    T = {int, float, char}, 
    unsigned int ...N = {0u, 1u, 2u}, 
    bp::tuple = std::basic_string<char> 
]': 

正是我們想要:)

1

如果您首先將參數提取到它們自己的包中,然後調用構造函數,可能會出現這種情況。其還遠沒有結束,但你的總體思路:

template <typename C, int N, typename... T> 
C* init_from_tuple(bp::tuple tpl, T... args) // enable_if N == sizeof...(T) 
{ 
    return new C{args...}; 
} 

template <typename C, int N, typename T0, typename... T> 
C* init_from_tuple(bp::tuple tpl, T... args) // enable_if N != sizeof...(T) 
{ 
    return init_from_tuple<C, N + 1>(tpl, args, bp::extract<T0>(tpl[N])); 
} 

template <typename C, typename... T> 
C* init_from_tuple(bp::tuple tpl, T... args) 
{ 
    return init_from_tuple<C, 0, T...>(tpl, args); 
} 

使用升壓轉換器的enable_if作出指示的地方只在某些情況下啓用,也可能是模板參數需要一些變化,但這是一個開始。