【问题标题】:Overloading std::transform algorithm重载 std::transform 算法
【发布时间】:2014-04-02 12:09:56
【问题描述】:

考虑标准使用 std::transform 算法:

vector<int> in = { 1, 2, 3 };
auto f0 = [](int val) { return val + 1; };
auto f1 = [](int val) { return val > 1; };

vector<int> out0(in.size()); 
std::transform(in.begin(), in.end(), out0.begin(), f0);
vector<bool> out1(in.size()); 
std::transform(in.begin(), in.end(), out1.begin(), f1);

这很好用,但写起来很长。我想写这样的东西:

auto out0 = tranform(in, f0);
auto out1 = tranform(in, f1);

如何重载转换算法以允许这种语法?

【问题讨论】:

  • 不需要声明尺寸。使用 std::back_inserter。

标签: c++ algorithm c++11 transform std


【解决方案1】:

以下应该做你想做的事

#include <algorithm>
#include <iostream>
#include <type_traits>
#include <vector>

template<typename T, typename F>
std::vector<typename std::result_of<F(T)>::type>
transform(const std::vector<T>& l, F func)
{
    typedef typename std::result_of<F(T)>::type FunctorReturnType;
    std::vector<FunctorReturnType> out(l.size());
    std::transform(l.begin(), l.end(), out.begin(), func);
    return out;
}

int main ()
{
    const std::vector<int> in{ 1, 2, 3 };
    auto f0 = [](int val) { return val + 1; };
    auto f1 = [](int val) { return val > 1; };

    auto out0 = transform(in, f0);
    auto out1 = transform(in, f1);

    for (const auto& m: out0) std::cout << m << std::endl;
    for (const auto& m: out1) std::cout << m << std::endl;
}

【讨论】:

  • 这实际上并不能编译,但可以很好地处理这个头文件:transform(const vector& l, F func) -> vector
  • 我投了反对票。我实际试用你的代码的时间比你多。你甚至没有尝试使用你的 trasnform 的混乱,你只是从你的 main() 调用 std::transform。
  • @DanielKO 感谢您让我知道。我的错,对不起,我正在努力让我的代码正常工作。
  • 该解决方案假定FunctorReturnType 是默认可构造的...否则您必须使用back_inseter
【解决方案2】:

你喜欢模板模板参数吗?这适用于比向量更多的容器。

template<template<class...> class C, class F, class T, class... Tail>
C<typename result_of<F(T)>::type>
transform(const C<T, Tail...>& in, F func)
{
    C<typename result_of<F(T)>::type> out(in.size());
    std::transform(in.begin(), in.end(), out.begin(), func);
    return out;
}

可以看到在http://coliru.stacked-crooked.com/a/767adb662d7cbe42工作

编辑:更改为在结果容器中不使用源分配器。

【讨论】:

  • 当你在结果容器中使用原始分配器而不将其重新绑定到新类型时,你可能会遇到一些奇怪的事情......
  • 该解决方案假定result_of&lt;F(T)&gt;::type 是默认可构造的...否则您必须使用std::back_inserter
  • 确实,我知道的所有 STL 实现都重新绑定了提供的分配器,但我在标准中找不到任何关于它的字眼。使用默认分配器可能更安全。
  • 关于 default-constructible,我遵循了提供的代码的框架,这就是为什么我没有费心进行琐碎的更改来使用 back_inserter。当已经对问题本身发表评论时,没有必要在每个答案上发布此内容。
【解决方案3】:

你为什么不接受以下不使用任何 C++11 魔法,例如 decltype 的内容?

#include <algorithm>
#include <vector>
template<class T, class F>
std::vector<T> transform(const std::vector<T>& l, F func)
{
  std::vector<T> out(l.size());
  std::transform(l.begin(), l.end(), out.begin(), func);
  return out;
}

【讨论】:

  • 那是因为他试图使用auto 来创建一个容器..这没有任何意义。
  • 不应该是std::vector&lt;T&gt; 吗?只需将auto 替换为std::vector&lt;T&gt; ...在这里看不到任何使用auto 的理由..
  • @hivert 看起来他想要他传递的函数的返回类型..这个问题写得不好..
  • @KoKuToru 并展示了对 C++11 概念的根本误解。
  • 你不能返回vector,因为函数可以返回任何其他类型。
猜你喜欢
  • 2021-03-04
  • 2016-04-22
  • 2021-10-25
  • 2018-12-16
  • 2022-11-22
  • 2016-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多