C++ integer_sequence

 1 #include <tuple>
 2 #include <iostream>
 3 #include <utility>
 4 
 5 template<typename F, typename T, std::size_t... I>
 6 decltype(auto) apply_impl(F f, const T& t, std::index_sequence<I...>)
 7 {
 8   return f(std::get<I>(t)...);
 9 }
10 
11 template<typename F, typename T>
12 decltype(auto) apply(F f, const T& t)
13 {
14     return apply_impl(f, t, std::make_index_sequence<std::tuple_size<T>::value>());
15 }
16 
17 
18 int main()
19 {
20   auto tp = std::make_tuple(1, 'A', 1.2);
21     
22   auto ld = [](int arg1, char arg2, double arg3)->int{
23       std::cout << "call func(" << arg1 << ", " << arg2 << ", " << arg3 << ")" << std::endl;
24       return 0;
25   };  
26     
27   int ret= apply(ld, tp);
28 }

参考:https://blog.poxiao.me/p/unpacking-a-tuple-to-call-a-function-in-cpp14/

这里需要注意的是,函数的模板参数推演。C++03/98时,是单个实参,推导出单个模板类型,例如t推导出T。C++11/14开始,参数包也能推导了,例如:

 1 template<int... Is>
 2 struct sequence{};
 3 
 4 template<int... Is>
 5 void foo( sequence<Is...> sq )
 6 {
 7     (std::cout << ... << Is);
 8 }
 9 
10 int main()
11 {
12     foo( sequence<1,3,5,7,9>() );
13 }

 既然interger_sequence这样重要,这里给出一个实现。

 1 #include <iostream>
 2 
 3 // This is the type which holds sequences
 4 template <int ... Ns> struct sequence {};
 5 
 6 // First define the template signature
 7 template <int ... Ns> struct seq_gen;
 8 
 9 // Recursion case
10 template <int I, int ... Ns>
11 struct seq_gen<I, Ns...>
12 {
13     // Take front most number of sequence,
14     // decrement it, and prepend it twice.
15     // First I - 1 goes into the counter,
16     // Second I - 1 goes into the sequence.
17     using type = typename seq_gen<
18         I - 1, I - 1 , Ns...>::type;
19 };
20 
21 // Recursion abort
22 template <int ... Ns>
23 struct seq_gen<0, Ns...>
24 {
25     using type = sequence<Ns...>;
26 };
27 
28 template <int N>
29 using sequence_t = typename seq_gen<N>::type;
30 
31 
32 template<int...Is>
33 void show( sequence<Is...>){
34     ( ((std::cout << " ") << Is) , ...) ;
35 }
36 
37 int main(){
38     show( sequence_t<10>() );
39 }

参考:https://blog.galowicz.de/2016/06/24/integer_sequences_at_compile_time/

原理解析:

sequence_t<10>类型是这个类型的别名:seq_gen<10>::type   见第29行
seq_gen<10>唯一能匹配的模板特化为:seq_gen<10, int...Ns> 。现在这个Ns是空列表{}。这是1个模板参数变成2组模板参数质的飞跃。我们用伪代码seq_gen<10, {}>表示
seq_gen<10, {}>::type 等价于seq_gen<10-1,10-1, {}>::type即seq_gen<9,9, {}>::type 见第18行
seq_gen<9,9, {}>唯一能匹配的模板特化为:seq_gen<9, int...Ns>。现在这个Ns是列表{9}。我们用伪代码seq_gen<9, {9}>表示.
seq_gen<9, {9}>::type 等价于seq_gen<9-1,9-1, {9}>::type即seq_gen<8,8, {9}>::type
seq_gen<8,8, {9}>唯一能匹配的模板特化为:seq_gen<8, int...Ns>。现在这个Ns是列表{8,9}。我们用伪代码seq_gen<8, {8,9}>表示.
......
seq_gen<0, {0,1,2,3,4,5,6,7,8,9}>唯一能匹配的模板特化为第22行,递归终结特化。
seq_gen<0, int...Ns>:::type等价于sequence<0,1,2,3,4,5,6,7,8,9>. 结束。

还有更具有效率的算法,有空可研究:https://stackoverflow.com/questions/17424477/implementation-c14-make-integer-sequence

posted @ 2018-03-28 15:14  thomas76  阅读(1766)  评论(0编辑  收藏  举报