
std::integer_sequence, std::index_sequence
Can make integer sequence in compile-time, so it is often used in compile-time indexing.
Defined in header <utility>
template<typename T, T... Ints>
class integer_sequence;
template<std::size_t ...Ints>
using index_sequence = integer_sequence<std::size_t, Ints...>;
std::index_sequence is specialization of std::integer_sequence, with it's first type as std::size_t(Since C++ standard uses std::size_t for indexing).
So you should be aware of it when computing with signed numbers.
Below is Helper Templates which can make incrementing integer sequence(0 to N-1)
template<typename T, T N>
std::make_integer_sequence<T, N> // std::integer_sequence that gets 0, 1, 2, ... N-1 as a template parameter
template<std::size_t N>
std::make_index_sequence<N> // std::index_sequence that gets 0, 1, 2, ... N-1 as a template parameter
template<typename ...Args>
std::index_sequence_for<Args...> // std::index_sequence that gets 0, 1, 2, ... sizeof...(Args)-1 as a template parameter
Example 1
template<typename T, std::size_t... I>
auto make_array(const std::vector<T>& vec, std::index_sequence<I...>){
return std::array<T, sizeof...(I)>{vec[I]...};
}
template<typename T>
void print_container(const T& arr){
for(const auto elem : arr)
std::cout << elem << " ";
std::cout << std::endl;
}
int main()
{
std::vector<int> v = {1, 2, 3, 4, 5, -1, -2, -3, -4, -5};
auto arr = make_array(v, std::make_index_sequence<3>());
print_container(arr);
print_container(make_array(v, std::index_sequence<1, 3, 5, 7>{}));
}
Outputs:
1 2 3
2 4 -1 -3
While calling make_array(v, std::make_index_sequence<3>())
1. std::make_index_sequence<3>() creates a std::index_sequence<0, 1, 2> object, and pass it to make_array function.
2. the template parameter of std::index_sequence is deduced
3. unpacking vector elements to std::initializer_list
4. construct std::array with it(which size has to be known at compile-time).
5. and returns the std::array
※ sizeof...() operator returns the total number of the parameter pack.
Same things are happening in make_array(v, std::index_sequence<1, 3, 5, 7>{}).
Since you are passing an std::index_sequence object, so you can use either parentheses(calling a default constructor) or a uniform initializer {}.
Example 2
It can also be used in accessing all members of tuple-like(std::pair, std::tuple) object, which doesn't provide its iterator.
template<typename T>
void print_all(const T& val){
std::cout << val << std::endl;
}
template<typename T, typename ...Ts>
void print_all(const T& val, const Ts&... vals){
std::cout << val << " ";
print_all(vals...);
}
template<typename ...Args, std::size_t... I>
void print_tuple_imp(const std::tuple<Args...>& tup, std::index_sequence<I...>){
print_all(std::get<I>(tup)...);
}
template<typename ...Args>
void print_tuple(const std::tuple<Args...>& tup){
print_tuple_imp(tup, std::index_sequence_for<Args...>());
}
int main()
{
print_tuple(std::make_tuple(1, 2, 3.14));
return 0;
}
Outputs
1 2 3.14
Since std::cout doesn't support parameter unpacking in below C++ 20, print_all function is used to print parameter packs.
print_tuple makes std::index_sequence<0, 1, 2> and pass it to print_tuple_imp.
print_tuple_imp is unpacking all tuple element and passing it to print_all.
You can make a custom integer sequence like the below.
template <std::size_t ... Is>
constexpr auto zero_sequence (std::index_sequence<Is...> const &)
-> decltype( std::index_sequence<0*Is...>{} ); // multiplying 0 to all template parameters
template <std::size_t N>
using make_zero_sequence
= decltype(zero_sequence(std::make_index_sequence<N>{}));
template<typename T>
void print_container(const T& arr){
for(const auto elem : arr)
std::cout << elem << " ";
std::cout << std::endl;
}
int main()
{
std::vector<int> v = {1, 2, 3, 4, 5, -1, -2, -3, -4, -5};
print_container(make_array(v, vmake_zero_sequence<10>()));
return 0;
}
Outputs
1 1 1 1 1 1 1 1 1 1
Questions, Feedbacks, and comments are very helpful to me!
'C++ > 레퍼런스(Reference)' 카테고리의 다른 글
C++ STL: std::rbegin, std::rend, std::crbegin, std::crend (0) | 2020.11.01 |
---|---|
C++ 레퍼런스: std::begin, std::end, std::cbegin, std::cend (2) | 2020.10.29 |