2012-01-11 17 views
6

我想編寫一個函數模板,apply,它接收一些功能f,整數i和參數包。 apply需要解壓縮參數和應用f對他們來說,除了i個參數,pi。對於pi,在將其作爲參數傳遞給f之前,需要調用其他函數g如何分區參數包?

看來,我需要一種方法來對參數包分割成左側,i個參數,和右側。這可能嗎?代碼:

template<int i, typename Function, typename... Parms> 
    void apply(Function f, Parms... parms) 
{ 
    auto lhs = // what goes here? 
    auto pi = // what goes here? 
    auto rhs = // what goes here? 

    f(lhs..., g(pi), rhs...); 
} 
+2

pi在math.h中可用作M_PI。不知道其餘的,你可以用更少的省略號發佈代碼嗎? – 2012-01-11 01:13:18

+2

@HansPassant我覺得OP意味着'第i parameter'通過'pi' – 2012-01-11 01:14:07

+5

@HansPassant C++現在去整個方式:你不必再編寫所有的代碼!省略號實際上是代碼並正在執行! – 2012-01-11 01:16:44

回答

3

好的,我們開始吧!它真的醜陋,但我不能趕緊拿出一個更好的版本;)大多數的東西是沼澤標準模板專業化。最大的問題是創建一個適當大小的整數列表。我似乎記得,我提出了一個很好的版本,但不知怎的,我不記得我做了什麼。請享用!

#include <iostream> 
#include <utility> 

// printing the values 
void print_args() {} 
template <typename F> void print_args(F f) { std::cout << f; } 
template <typename F, typename... T> 
void print_args(F f, T... args) 
{ 
    std::cout << f << ", "; 
    print_args(args...); 
} 

// the function object to be called: 
struct Functor 
{ 
    template <typename... T> 
    void operator()(T... args) 
    { 
     std::cout << "f("; 
     print_args(args...); 
     std::cout << ")\n"; 
    } 
}; 

// conditionally apply g(): 
template <typename T> T g(T value) { return 1000 + value; } 
template <int i, int j, typename T> 
typename std::enable_if<i != j, T>::type forward(T t) { return t; } 
template <int i, int j, typename T> 
typename std::enable_if<i == j, T>::type forward(T t) { return g(t); } 

// create a series of integers: 
template <int... Values> struct values {}; 

template <int Add, typename> struct combine_values; 
template <int Add, int... Values> 
struct combine_values<Add, values<Values...>> 
{ 
    typedef values<Values..., Add> type; 
}; 

template <int Size> struct make_values; 
template <> struct make_values<0> { typedef values<> type; }; 
template <int Size> 
struct make_values 
{ 
    typedef typename combine_values<Size, typename make_values<Size -1>::type>::type type; 
}; 

// applying f(t...) except for ti where g(ti) is called 
template <int i, int... Values, typename Function, typename... T> 
void apply_aux(values<Values...>, Function f, T... t) 
{ 
    f(forward<i, Values>(t)...); 
} 

template <int i, typename Function, typename... T> 
void apply(Function f, T... t) 
{ 
    apply_aux<i>(typename make_values<sizeof...(T)>::type(), f, t...); 
} 

int main() 
{ 
    apply<3>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8); 
    apply<4>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8); 
    apply<5>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8); 
} 
+0

結束了使用這一個。謝謝! – 2012-01-12 01:19:03

3

實際上在前一段時間,類似的代碼實現了。因此,嘗試下面的代碼:

template<unsigned N, unsigned M> 
struct call_up_impl{ 
    template<class Func, class Mutator, class Tuple, class... Args> 
    static void do_call(const Func& func, const Mutator& mutator, const Tuple& args, Args&&... unpacked_args) { 
     call_up_impl<N-1, M>::do_call(func, mutator, args, std::get<N-1>(args), std::forward<Args>(unpacked_args)...); 
    } 
}; 

template<unsigned M> 
struct call_up_impl<0, M> { 
    template<class Func, class Mutator, class Tuple, class... Args> 
    static void do_call(const Func& func, const Mutator&, const Tuple&, Args&&... unpacked_args) { 
     func(std::forward<Args>(unpacked_args)...); 
    } 
}; 
template<unsigned M> 
struct call_up_impl<M, M> { 
    template<class Func, class Mutator, class Tuple, class... Args> 
    static void do_call(const Func& func, const Mutator& mutator, const Tuple& args, Args&&... unpacked_args) { 
     call_up_impl<M-1, M>::do_call(func, mutator, args, mutator(std::get<M-1>(args)), std::forward<Args>(unpacked_args)...); 
    } 
}; 
template<int i, typename Function, typename... Parms> 
void apply(Function f, Parms... parms) { 
     std::tuple<Parms...> t(parms...); 
     call_up_impl<std::tuple_size<decltype(t)>::value, i + 1>::do_call(f, &g, t); 
} 

這是我原來的代碼快速適應,所以它不是徹底的測試,也許不是不是最佳的方式做到這一點,但它應該工作至少(至少根據快速測試,並取決於你想要什麼)。應該可以在沒有元組的情況下做到這一點,但我還沒有得到這個用g ++編譯(它似乎不喜歡所需的嵌套variadic模板)。然而改變apply到:

template<int i, typename Function, typename... Parms> 
void apply(Function f, Parms&&... parms) { 
     std::tuple<Parms&&...> t(std::forward<Parms>(parms)...); 
     call_up_impl<std::tuple_size<decltype(t)>::value, i + 1>::do_call(f, &g, t); 
} 

將可能避免了大部分的元組引入的開銷。如果要正確轉發std::get調用的結果會更好,但我現在太累了,無法將其寫入。

+0

我認爲這看起來更復雜,也取決於'std :: tuple'做所有的工作!當然,我也使用一個標準類('std :: enable_if'),但與'std :: tuple'相比,'std :: enable_if'的實現更簡單。我的很多代碼實際上也是應用這個操作並打印結果。 – 2012-01-11 02:11:41

+0

@DietmarKühl:我不同意看起來更復雜的部分。如果我們僅僅因爲使用可變參數模板而被綁定到C++ 11,那麼依賴於'std :: tuple'會出現什麼問題呢?(除了使用可變元素模板實現必要的元組操作也非常容易)。那麼問題是什麼? – Grizzly 2012-01-11 02:26:25

+0

這兩種解決方案都很有趣。感謝您提供他們。不過,我感到失望的是,在C++ 11中沒有更多的直接解決方案。 – 2012-01-11 22:00:32