分割std :: index_sequence时出错

时间:2014-01-01 23:33:03

标签: c++ templates c++11 std

我正在尝试将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>{});
}

我已经尝试使用最新版本的 Clang GCC MSVC ,但它们都无法推断{{1} }。标准是否允许这样做?如果没有,为什么以及什么是实现我的意图的好方法?

5 个答案:

答案 0 :(得分:6)

  

14.8.2.5/9 ...如果P的模板参数列表包含的包扩展不是最后一个模板参数,则整个模板参数列表为非演绎语境......

因此,在将index_sequence<I..., J...>index_sequence<0, 1>{}进行比较时,无法推断I...J...

答案 1 :(得分:6)

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

我将省略std::index_sequence和朋友的实施,因为您可以参考论文N3658和示例实施here

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>;

由于我们没有类似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>());
}

split_at

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

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));
}

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>>>(), "");

答案 2 :(得分:2)

要获得后缀,您可以使用以下内容:

template<int ... I> struct get_suffix_helper {
    template<int ... J> static index_sequence<J...> foo(index_sequence<I..., J...>);
};

template<typename T1, typename T2> struct get_suffix;

template<int ... Is1, int ... Is2>
struct get_suffix<index_sequence<Is1...>, index_sequence<Is2...>> :
    public decltype(get_suffix_helper<Is1...>::foo(std::declval<index_sequence<Is2...>>())) {};

static_assert(std::is_base_of<index_sequence<>,
                              get_suffix<index_sequence<1, 2>,
                                         index_sequence<1, 2>>>::value, "error");

static_assert(std::is_base_of<index_sequence<42>,
                              get_suffix<index_sequence<1, 2>,
                                         index_sequence<1, 2, 42>>>::value, "error");

或者,通过一些错误检查:

template <typename T1, typename T2> struct get_suffix;

template<int ...Is>
struct get_suffix<index_sequence<>, index_sequence<Is...>>
{
    typedef index_sequence<Is...> type;
    static const bool valid = true;
};

template<int ...Is>
struct get_suffix<index_sequence<Is...>, index_sequence<>>
{
    typedef void type;
    static const bool valid = false;
};

template<>
struct get_suffix<index_sequence<>, index_sequence<>>
{
    typedef index_sequence<> type;
    static const bool valid = true;
};

template<int N, int ...Is, int... Js>
struct get_suffix<index_sequence<N, Is...>, index_sequence<N, Js...>>
{
    typedef typename get_suffix<index_sequence<Is...>, index_sequence<Js...>>::type type;
    static const bool valid = get_suffix<index_sequence<Is...>, index_sequence<Js...>>::valid;
};

template<int N1, int N2, int ...Is, int... Js>
struct get_suffix<index_sequence<N1, Is...>, index_sequence<N2, Js...>>
{
    typedef void type;
    static const bool valid = false;
};

static_assert(std::is_same<index_sequence<>,
                           get_suffix<index_sequence<1, 2>,
                                      index_sequence<1, 2>>::type>::value, "error");

static_assert(!get_suffix<index_sequence<1, 2, 42>, index_sequence<1, 2>>::valid, "error");
static_assert(!get_suffix<index_sequence<0, 2, 1>, index_sequence<0, 1, 2>>::valid, "error");

static_assert(std::is_same<index_sequence<42>,
                           get_suffix<index_sequence<1, 2>,
                                      index_sequence<1, 2, 42>>::type>::value, "error");

答案 3 :(得分:0)

不是答案,而是一种解决方法:递归修剪领先元素a la:

template <typename, typename> struct remove_prefix;

template <std::size_t... I>
struct remove_prefix<index_sequence<>, index_sequence<I...>> {
  using type = index_sequence<I...>;
};

template <std::size_t First, std::size_t... I, std::size_t... J>
struct remove_prefix<index_sequence<First, I...>,
                     index_sequence<First, J...>> {
  using type = typename remove_prefix<index_sequence<I...>,
                                      index_sequence<J...>>::type;
};

Demo at Coliru

答案 4 :(得分:0)

我需要在特定位置将i​​ndex_sequence拆分为头部和尾部,这是我想出的实现方式:

template<size_t N, typename Lseq, typename Rseq>
struct split_sequence_impl;

template<size_t N, size_t L1, size_t...Ls, size_t...Rs>
struct split_sequence_impl<N,index_sequence<L1,Ls...>,index_sequence<Rs...>>  { 
  using next = split_sequence_impl<N-1,index_sequence<Ls...>,index_sequence<Rs...,L1>>;
  using head = typename next::head;
  using tail = typename next::tail;
};

template<size_t L1, size_t...Ls, size_t...Rs>
struct split_sequence_impl<0,index_sequence<L1,Ls...>,index_sequence<Rs...>> {
  using tail = index_sequence<Ls...>;
  using head = index_sequence<Rs...,L1>;
};

template<typename seq, size_t N> 
using split_sequence = split_sequence_impl<N-1,seq,empty_sequence>;

template<typename seq, size_t N>
using sequence_head_t = typename split_sequence<seq,N>::head;

template<typename seq, size_t N>
using sequence_tail_t = typename split_sequence<seq,N>::tail;