方便函数/宏用于std :: transform

时间:2014-08-13 10:57:36

标签: c++ templates macros

为了好玩,我尝试将std::transform的使用尽可能接近map in Haskell

我目前的尝试看起来如下,但我想它可以做得更好。

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

using namespace std;

template<typename ContainerOut, typename ContainerIn, typename Functor>
ContainerOut mappHelp(const ContainerIn& xs, Functor op)
{
    ContainerOut res;
    res.reserve(xs.size());
    transform(begin(xs), end(xs), back_inserter(res), op);
    return res;
}

#define mapp(f, xs, res) mappHelp<decltype(res)>(xs, [](decltype(xs)::value_type it)f);

int main()
{
    vector<int> xs = {1,2,3};

    // How can we come closer to the following?
    // auto ys = mapp({return it * 1.5;}, xs);
    vector<double> ys = mapp({return it * 1.5;}, xs, ys);

    copy(begin(ys), end(ys), ostream_iterator<double>(std::cout, ","));
}

关于如何摆脱必须告诉返回类型的一些想法(或者一般如何改进它)?

1 个答案:

答案 0 :(得分:2)

您可以执行以下操作:

// helper class to rebind a container to use an other type
template<typename Container, typename T> struct rebind;

// specialization for vector
template <typename Tc, typename A, typename T>
struct rebind<std::vector<Tc, A>, T>
{
    using type = std::vector<T, typename A::template rebind<T>::other>;
};

和你的方法

template<
    typename F,
    typename C,
    typename ContainerOut =
        typename rebind<C, decltype(std::declval<F>()(*std::begin(std::declval<C>())))>::type
    >
ContainerOut
 mapp(F f, const C& c)
{
    ContainerOut res;
    res.reserve(c.size());
    std::transform(std::begin(c), std::end(c), std::back_inserter(res), f);
    return res;
}

Live example