std::make_index_sequence的简单实现和简单应用

前言

之前翻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,所以这里和一般的concat不太一样,直接把1到N-1的计算也放进去了

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

你可能感兴趣的:(std::make_index_sequence的简单实现和简单应用)