拆分std :: index_sequence时出错

K-b*_*llo 4 c++ templates std c++11

我试图分index_sequence成两半.为此,我index_sequence使用下半部分生成一个并使用它来跳过完整的前导元素index_sequence.以下是一个最小的测试用例,代表了我正在努力实现的目标:

template <int ...I>
struct index_sequence {};

template <int ...I, int ...J>
void foo(index_sequence<I...>, index_sequence<I..., J...>)
{}

int main()
{
    foo(index_sequence<0>{}, index_sequence<0, 1>{});
}
Run Code Online (Sandbox Code Playgroud)

我用最新版本的Clang,GCCMSVC试过这个,但它们都没有推断出来J....标准是否允许这样做?如果没有,为什么以及什么是实现我的意图的好方法?

Igo*_*nik 6

14.8.2.5/9 ...如果模板参数列表P包含的包扩展不是最后一个模板参数,则整个模板参数列表是非推导的上下文...

因此,在index_sequence<I..., J...>与之比较时index_sequence<0, 1>{},既I...不能J...也不能推断.


mpa*_*ark 6

如果你想要的是拆分std::index_sequence而不是删除两个公共前缀std::index_sequence,我认为你可以从一个实现中受益slice并使用它来分割std::index_sequence成碎片.

我将省略std::index_sequence和朋友的实现,因为你可以参考文章,N3658,以及这里的示例实现.

make_index_range

为了实现slice,我们将使用一个名为的帮助器make_integer_range.我们想要一个std::index_sequence生成器,它给我们[Begin,End]而不是[0,End].利用std::make_integer_sequence,我们得到:

template <typename T, typename Seq, T Begin>
struct make_integer_range_impl;

template <typename T, T... Ints, T Begin>
struct make_integer_range_impl<T, std::integer_sequence<T, Ints...>, Begin> {
  using type = std::integer_sequence<T, Begin + Ints...>;
};

/* Similar to std::make_integer_sequence<>, except it goes from [Begin, End)
   instead of [0, End). */
template <typename T, T Begin, T End>
using make_integer_range = typename make_integer_range_impl<
    T, std::make_integer_sequence<T, End - Begin>, Begin>::type;

/* Similar to std::make_index_sequence<>, except it goes from [Begin, End)
   instead of [0, End). */
template <std::size_t Begin, std::size_t End>
using make_index_range = make_integer_range<std::size_t, Begin, End>;
Run Code Online (Sandbox Code Playgroud)

切片

由于我们没有类似std::get的功能std::index_sequence或可变参数模板包,我们只是构建一个临时的std::array来获取我们std::get.然后只使用我们想要的切片来爆炸数组.

template <std::size_t... Indices, std::size_t... I>
constexpr decltype(auto) slice_impl(
      std::index_sequence<Indices...>,
      std::index_sequence<I...>) {
  using Array = std::array<std::size_t, sizeof...(Indices)>;
  return std::index_sequence<std::get<I>(Array{{Indices...}})...>();
}

template <std::size_t Begin, std::size_t End, std::size_t... Indices>
constexpr decltype(auto) slice(std::index_sequence<Indices...> idx_seq) {
  return slice_impl(idx_seq, make_index_range<Begin, End>());
}
Run Code Online (Sandbox Code Playgroud)

split_at

使用slice我们刚刚构建的一个例子是编写一个split_at函数.我们指定要分割的索引std::index_sequence,并std::index_sequence在给定索引处返回一对s split.

template <std::size_t At, std::size_t... Indices>
constexpr decltype(auto) split_at(index_sequence<Indices...> idx_seq) {
    return std::make_pair(slice<0, At>(idx_seq), 
                          slice<At, sizeof...(Indices)>(idx_seq));
}
Run Code Online (Sandbox Code Playgroud)

例子split_at:

static_assert(std::is_same<
                decltype(split_at<2>(index_sequence<1, 4, 2>())),
                std::pair<index_sequence<1, 4>, index_sequence<2>>>(), "");

static_assert(std::is_same<
                decltype(split_at<1>(index_sequence<1, 4, 2, 3>())),
                std::pair<index_sequence<1>, index_sequence<4, 2, 3>>>(), "");
Run Code Online (Sandbox Code Playgroud)