日記

内容の正しさは保証しません

インデックス付きtransform

jsのように添え字が欲しいことがあったので書いた。

#include <type_traits>
#include <algorithm>

struct result_of
{
    template <class T, class R>
    struct y {
        using type = R;
        static inline constexpr bool value = T::value;
    };
    
    template <class C, class F, class... Args>
    static auto f() -> y<std::false_type, std::invoke_result_t<F&, Args...>>;
    
    template <class C, class F, class... Args>
    static auto f() -> y<std::true_type, std::invoke_result_t<F&, Args..., C>>;
};

template <class C, class F, class... Args>
using result_of_t = decltype(result_of::f<C, F, Args...>());

//添え字を与えてくれるstd::transform
template <
    template <class...> class C, 
    class... Args,
    class F,
    class R = result_of_t<std::size_t, F, typename C<Args...>::value_type>
>
static inline auto transform(C<Args...> const& t, F&& f)
{
    //Cはテンプレート引数を省略できるとする
    auto u = C<typename R::type>(t.size());
    
    if constexpr (R::value)
    {
        std::transform(t.begin(), t.end(), u.begin(), [&f](auto const& x) {
            static size_t i = 0;
            return f(x, i++);
        });
    }
    else {
        std::transform(t.begin(), t.end(), u.begin(), f);
    }
    return u;
}

result_of_t<C, F, Args...>::valueはファンクタをArgs..., Cで呼び出せるならtrue, そうでないときはfalseとなる。またresult_of_t<C, F, Args...>::typeはファンクタの返り値の型である。

#include <iostream>
#include <vector>
int main() {
    auto v = transform(std::vector{2, 4, 6, 8}, [](auto x, auto i) {
        std::cout << i << ":" << x * i << std::endl;
        return x * i; 
    });
}

結果

0:0
1:4
2:12
3:24