C++14中如何反转任意std::integer_sequence的整数顺序
问题描述
我有时需要反转index_sequence中的值,再使用反转后的结果反转类元组(tuple-like)对象内的元素,例如下方示例就实现了编译期反转constexpr修饰的std::array:
#include <array> #include <cstdint> #include <utility> namespace detail { template <class T, std::size_t N, std::size_t... I> constexpr std::array<T, N> rev_arr_helper(const std::array<T, N>& arr, std::index_sequence<I...>) { return {arr[sizeof...(I) - I - 1]...}; // {arr[4-0-1], arr[4-1-1], arr[4-2-1], arr[4-3-1]} // => // {arr[3], arr[2], arr[1], arr[0]} } } // namespace detail template <class T, std::size_t N> constexpr std::array<T, N> rev_arr(const std::array<T, N>& arr) { return detail::rev_arr_helper(arr, std::make_index_sequence<N>{}); } int main() { constexpr std::array<int, 4> arr{11, 22, 33, 44}; constexpr auto rev = rev_arr(arr); static_assert(rev[0] == 44 && rev[1] == 33 && rev[2] == 22 && rev[3] == 11, ""); }
但上述方案仅支持元素按0, 1, 2, ..., N-1顺序排列的索引序列,无法适配任意integer_sequence(例如std::integer_sequence<int, 4, -5, 7, -3>)。需要在C++14标准下让如下代码可正常编译:
#include <type_traits> #include <utility> int main() { std::integer_sequence<int, 4, -5, 7, -3> iseq; std::integer_sequence<int, -3, 7, -5, 4> itarget; auto irev = reverse_sequence(iseq); static_assert(std::is_same<decltype(irev), decltype(itarget)>::value, ""); }
需要实现通用的reverse_sequence功能达成上述需求。
实现方案
原有反转array的方案本质是直接计算反转后的索引值,仅适配连续0起始的索引序列,通用实现通过存储原序列所有值、按位置反向取值的逻辑,即可支持任意值的整数序列反转,完全符合C++14标准要求。
完整实现代码如下:
#include <type_traits> #include <utility> namespace detail { template <class T, T... Vals, std::size_t... Idx> constexpr auto reverse_sequence_helper(std::integer_sequence<T, Vals...>, std::index_sequence<Idx...>) { constexpr T val_arr[] = {Vals...}; return std::integer_sequence<T, val_arr[sizeof...(Idx) - 1 - Idx]...>{}; } } // namespace detail template <class T, T... Vals> constexpr auto reverse_sequence(std::integer_sequence<T, Vals...> seq) { return detail::reverse_sequence_helper( seq, std::make_index_sequence<sizeof...(Vals)>{} ); }
实现逻辑
- 对外接口接收任意
std::integer_sequence实例,自动推导序列元素类型和所有元素值 - 调用辅助函数时,通过
std::make_index_sequence生成和原序列长度一致、从0起始的连续索引序列 - 辅助函数中将原序列的所有元素存入
constexpr数组,包展开时按「序列长度-1-当前索引」的规则从数组中取对应位置的值,构造出反转后的新std::integer_sequence返回
注:该实现同时兼容std::index_sequence(其本身是std::integer_sequence<std::size_t, ...>的类型别名),可直接复用在类元组元素反转、编译期序列变换等场景中。
将上述实现和测试代码联合编译,可正常通过static_assert类型校验,返回结果和预期的反转后序列完全一致。
内容的提问来源于stack exchange,提问作者Ted Lyngmo
相关产品推荐
相关产品推荐

