【问题标题】:Apply a binary operator to each element in an array将二元运算符应用于数组中的每个元素
【发布时间】:2019-05-04 21:48:11
【问题描述】:

给定一个二进制仿函数(或类仿函数)对象,它接受两个 T* 类型的数组和一个大小并返回 T*,将这个仿函数应用于数组中的每个对象的规范方法是什么,返回一个新的?

即,与以下内容等效但更短且更不易出错的内容:

template<typename T, typename O>
T* apply(const T* a1, const T* a2, size_t size, O op) {
  T* out = new[size];
  for (size_t i = 0; i < size; i++) {
    out[i] = op(a1[i], a2[i]);
  }
  return out;
}

我对如何分配输出的细节并不太在意。在上面的示例中,它是在堆上分配的,但可能其他变体会覆盖其中一个输入或写入提供的缓冲区,或者它可能正在使用 std::array&lt;&gt; 并返回它,等等。

【问题讨论】:

  • 很确定 stl 中的模式是使用输出迭代器(例如,std::back_inserter)。
  • @StephenNewell - 当然,但是“从两个不同的范围迭代元素对”部分怎么样?这就是我坚持的部分。
  • 对不起,我把你的代码误读为op(a1[i], a1[i])。为什么不只使用两个迭代器并在每个迭代器上使用std::advance?是否要让调用者确保两个范围的大小相同取决于您(看起来std::equal 具有同时采用三个和四个迭代器的形式)。
  • 我想你可以使用std::transform() 的版本,它接收两个输入迭代器和一个二元运算符(this page 中的版本 3 或 4)
  • @max66 - 谢谢,这是我正在寻找的答案。不知何故,我仍然没有意识到这些形式......

标签: c++ templates c++14 array-algorithms


【解决方案1】:

您提到使用数组,但是使用带有迭代器/指针的函数,其中我们丢失了数组中的类型信息,类似于 C 样式的 C 样式处理中的数组到指针衰减数组参数。

如果适用(考虑到调用站点的限制),您可以改用std::array 来避免大小信息的丢失,同时仍然编写一个与大小无关的函数模板,其约束条件是两个数组参数都应该是相同的大小(我们可以预期您正在执行典型的 zip 和 map 操作)。

例如使用std::transform 将二元运算符应用于 to 数组参数中的成对元素:

#include <algorithm>
#include <array>
#include <iostream>

template <typename T, typename BinaryOperator, std::size_t N>
auto apply(const std::array<T, N>& arr1, const std::array<T, N>& arr2,
           const BinaryOperator& op) {
  std::array<T, N> result{};
  std::transform(arr1.begin(), arr1.end(), arr2.begin(), result.begin(), op);
  return result;
}

int main() {
  const std::array<int, 5> arr1 = {1, 2, 3, 4, 5};
  const std::array<int, 5> arr2 = {6, 7, 8, 9, 10};
  const auto results = apply(arr1, arr2, [](int i, int j) { return i + j; });
  for (const auto num : results) {
    std::cout << num << " ";
  }  // 7 9 11 13 15
}

或者,如果你可以使用 C++14,std::integer_sequence 结合参数包扩展:

#include <array>
#include <iostream>
#include <utility>

namespace detail {
template <typename Array, typename BinaryOperator, std::size_t... I>
Array apply_impl(const Array& arr1, const Array& arr2, const BinaryOperator& op,
                 std::index_sequence<I...>) {
  return {op(arr1[I], arr2[I])...};
}
}

template <typename T, typename BinaryOperator, std::size_t N,
          typename Indices = std::make_index_sequence<N>>
auto apply(const std::array<T, N>& arr1, const std::array<T, N>& arr2,
           const BinaryOperator& op) {
  return detail::apply_impl(arr1, arr2, op, Indices{});
}

int main() {
  const std::array<int, 5> arr1 = {1, 2, 3, 4, 5};
  const std::array<int, 5> arr2 = {6, 7, 8, 9, 10};
  const auto results = apply(arr1, arr2, [](int i, int j) { return i + j; });
  for (const auto num : results) {
    std::cout << num << " ";
  }  // 7 9 11 13 15
}

【讨论】:

  • 感谢您的回答!是的,我在这里松散地使用术语“数组”来表示在内存中具有数组类型但作为指针/大小对传递的东西,不一定在函数中具有编译时数组类型的东西。这是在 C++ 中处理数组的常见情况。一般来说,我希望我的对象在编译时具有未知的动态大小,所以对于我正在做的 std::array 来说,vector&lt;&gt; 可能是一个更好的容器模拟。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-10
  • 1970-01-01
  • 1970-01-01
  • 2022-01-21
相关资源
最近更新 更多