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