前言
之前翻cpp-reference翻到一个有趣的东西:
sequenceen.cppreference.com
其中有一条
template
using make_integer_sequence = std::integer_sequence;
起初没有仔细想,以为这种将一个参数N拆出N个元函数参数的效果是靠编译器开洞实现的,像std::declval那样,只有申明没有定义,后来在某个应用场景下用到了这玩意,又仔细考虑了一下,发现这玩意其实是可以实现的,下面给一个简单的实现。
正文
首先定义sequence
template
struct seq {
using type = seq;
};
然后是concat,用以将两个sequence拆包再拼起来,因为处理目标是实现make_index_sequence
template
struct concat;
template
struct concat, seq> : public seq {
};
最后是make
template
struct make : public concat, typename make::type> {
};
template<>
struct make<1> : public seq<0> {
};
template<>
struct make<0> : public seq<> {
};
测试一下:
template
constexpr size_t get(seq q) {
if constexpr (N == 0) {
return F;
} else {
return get(seq{});
}
}
void make_test() {
auto seq = make<4>{};
static_assert(get<0>(seq) == 0, "");
static_assert(get<1>(seq) == 1, "");
static_assert(get<2>(seq) == 2, "");
static_assert(get<3>(seq) == 3, "");
}
简单的使用
C++标准给出这样一个东西肯定是有用的,那么怎么用呢?最简单的可以用来迭代。
比如你有一个函数,作用是将传入的tuple的每一个元素加上1再返回
template
std::tuple succ(std::tuple tup) {
// how to add it?
}
有了make_sequence之后你可以这样:
template
struct succ_impl;
template
struct succ_impl> {
template
static constexpr decltype(auto) apply(std::tuple arg) {
return std::make_tuple( (std::get(arg) + 1)... );
}
};
template
constexpr std::tuple succ(std::tuple arg) {
return succ_impl::type>::apply(arg);
}
简单的测试一下:
void succ_test() {
constexpr std::tuple tup(1, 2, 0, 4);
constexpr auto new_tup = succ(tup);
static_assert(std::get<0>(new_tup) == 2, "");
static_assert(std::get<1>(new_tup) == 3, "");
static_assert(std::get<2>(new_tup) == 1, "");
static_assert(std::get<3>(new_tup) == 5, "");
}