constexpr な transform_view

Sequence の変換を行うラッパーです。
[] などで Sequence へアクセスする際に変換を行います。

[ソース]

#include <utility>
#include <type_traits>

namespace ce{

template<std::size_t... Indices>
struct index_tuple{};

template<
    std::size_t Start,
    std::size_t Finish,
    std::size_t Step = 1,
    typename Acc = index_tuple<>,
    bool Break = (Start >= Finish)
>
struct index_range{
    typedef Acc type;
};

template<
    std::size_t Start, std::size_t Finish, std::size_t Step,
    std::size_t... Indices
>
struct index_range<Start, Finish, Step, index_tuple<Indices...>, false>
    : index_range<Start + Step, Finish, Step, index_tuple<Indices..., Start>>
{};

template<typename Seq>
struct value_type;

template<typename Seq>
struct size;

template<std::size_t Index, typename Seq>
constexpr auto
at(Seq const& seq)->decltype(seq[Index]){
    return seq[Index];
}

template<typename T, std::size_t N>
struct array{
    typedef T value_type;
    static std::size_t const size = N;

    constexpr T const&
    operator [](std::size_t n) const{
        return elems[n];
    }

    T elems[N ? N : 1];
};

template<typename T, typename ...Args>
constexpr array<T, sizeof...(Args)+1>
make_array(T t, Args... args){
    return {{ t, args... }};
}

template<typename T, std::size_t N>
struct value_type<array<T, N>>{
    typedef T type;
};

template<typename T, std::size_t N>
struct size<array<T, N>> : std::integral_constant<std::size_t, N>{};


template<typename Seq, typename Func>
struct transform_sequence{
    typedef typename std::result_of<
        Func(typename value_type<Seq>::type)
    >::type value_type;
    typedef transform_sequence<Seq, Func> this_type;

    constexpr value_type
    operator [](std::size_t n) const{
        return func(seq[n]);
    }
    Seq const& seq;
    Func  func;
};

template<typename Seq, typename Func>
struct value_type<transform_sequence<Seq, Func>> : value_type<Seq>{};

template<typename Seq, typename Func>
struct size<transform_sequence<Seq, Func>> : size<Seq>{};

template<typename Seq, typename Func>
constexpr transform_sequence<Seq, Func>
transform_view(Seq const& seq, Func func){
    return { seq, func };
}

template<typename Seq, std::size_t ...Indices>
constexpr array<
    typename value_type<Seq>::type,
    size<Seq>::value
>
copy_impl(Seq const& seq, index_tuple<Indices...>){
    return {{ at<Indices>(seq)... }};
}

template<typename Seq>
constexpr auto
copy_impl(Seq const& seq)
->decltype(copy_impl(seq, typename index_range<0, size<Seq>::value>::type())){
    return copy_impl(seq, typename index_range<0, size<Seq>::value>::type());
}

template<typename Seq>
constexpr auto
copy(Seq const& seq)->decltype(copy_impl(seq)){
    return copy_impl(seq);
}

}  // namespace ce


constexpr int
plus1(int n){
    return n + 1;
};

int
main(){
    static constexpr auto v = ce::make_array(1, 2, 3);
    static constexpr auto v2 = ce::transform_view(v, plus1);
    static_assert(v2[0] == 2, "");
    
    // 一時オブジェクトは保持できないので
//    static constexpr auto v3 = ce::transform_view(ce::make_array(1, 2, 3), plus1);
    // コピーする必要がある
    static constexpr auto v3 = ce::copy(
        ce::transform_view(ce::make_array(1, 2, 3), plus1)
    );
    static_assert(v3[1] == 3, "");
    return 0;
}

Sequence の参照を保持するのでちょっと怖いですが、こっちの方が効率は良さげな気がしますね。
iterator をどうするか…。

[コンパイラ]

  • g++ (GCC) 4.7.0 20111001 (experimental)

[参照]