日記

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

ノート 7/24

std::transformは処理を適用・結果を格納するコンテナの範囲をイテレータとして受け取る関数だが、一々

std::vector<int> w(v.size());
std::transform(v.begin(), v.end(), w.begin(), w.end(), f);

と書くのが面倒な上、二行も使う。 そこで、コンテナvの参照と関数fから上記の処理をしてwを返すようなラッパが欲しい。

テンプレートテンプレート

クラステンプレート(名前だけでは不完全な型)をテンプレートで表すにはテンプレートテンプレートを使う。

template <class T>
sturct A {
    T t;
};

//Tとしてstruct Aを指定できる
template <template <class> class T>
struct B {
    T<double> t;
};

実引数からクラステンプレートを推論させる

template <template <class> class T, class U>
void f(T<U>);
  • 上記の関数fにA<int>{}を与えた場合、T=A, U=intと判断される。

実装する

template <
    template <class...> class C
    class... Args,
    class F,
    class R = typename std::invoke_result_t<F&, typename C<Args...>::value_type const&>
>
auto transform(C<Args...> const& t, F&& f)
{
    //Args...の中でR以外のパラメータは省略可能と仮定する
    auto u = C<R>(t.size()); 
    std::transform(t.begin(), t.end(), u.begin(), f);
    return u;
}
  • template <class...> class Cは任意のコンテナを表すことができる
  • Args...はCのテンプレート引数
  • Fはファンクタ
  • RはFをCの要素に適用して返ってくる値の型
  • transform関数の第一引数では上で述べた推論を利用している。例えばstd::vector<int, std::allocator<int>>{}を与えればC=std::vector, Args...=int, std::allocator<int>になる。

欠点

  • std::mapは引数にstd::pair<S, T>を取らないためC<R>の実体化に失敗してコンパイルエラー.何か工夫が必要

参考

transformをラップして変換後のオブジェクトを返すようにしてみる - Qiita