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 をどうするか…。