在 cpp 中构建一个类似“map”的通用函数

Bub*_*aya 1 c++ templates

考虑

template <typename S, typename T, typename F>
vector<T> map(const vector<S> &ss, F f){
    vector<T> ts;
    ts.reserve(ss.size());
    std::transform(ss.begin(), ss.end(), std::back_inserter(ts), f);
    return ts;
}

int main(){
    vector<int> is = {...};
    vector<double> ts = map(is, [](int i){return 1.2*i;});
}
Run Code Online (Sandbox Code Playgroud)

因为编译器“无法推导出模板参数 T”。指定map类型

template <typename S, typename T>
vector<T> map(const vector<S> &ss, std::function<T(S)> f)
Run Code Online (Sandbox Code Playgroud)

也不起作用,因为它与 lambda 不匹配。

正确的方法是什么?

Hol*_*Cat 7

像这样的东西:

template <typename S, typename F>
auto map(const std::vector<S> &ss, F f) -> std::vector<std::decay_t<decltype(f(ss[0]))>>
{
    std::vector<std::decay_t<decltype(f(ss[0]))>> ts;
    ts.reserve(ss.size());
    std::transform(ss.begin(), ss.end(), std::back_inserter(ts), std::move(f));
    return ts;
}
Run Code Online (Sandbox Code Playgroud)

我选择了尾随返回类型,以便能够f在. 您可以只使用返回类型,但显式指定类型会使函数 SFINAE 友好。ssdecltypeauto


或者,一个稍微过度设计的版本,具有最热门的 C++20 功能:

template <
    template <typename...> typename C = std::vector,
    typename S, typename F
>
[[nodiscard]] C<std::decay_t<std::indirect_result_t<F, std::ranges::iterator_t<S>>>>
map(S &&ss, F f)
{
    C<std::decay_t<std::indirect_result_t<F, std::ranges::iterator_t<S>>>> ts;
    ts.reserve(std::ranges::size(ss));
    std::ranges::transform(ss, std::back_inserter(ts), std::move(f));
    return ts;
}
Run Code Online (Sandbox Code Playgroud)

  • @Bubaya基本上第二个允许你调用像`auto ts = map&lt;std::vector&gt;(is, [](int i) {return 1.2 * i; });`这样的函数 (2认同)