我正在尝试将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} }。标准是否允许这样做?如果没有,为什么以及什么是实现我的意图的好方法?
答案 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。
要实施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>());
}
使用我们刚刚构建的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;
};
答案 4 :(得分:0)
我需要在特定位置将index_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;