在 std::valarray<T> 上使用 .sum() 和 +=

Using .sum() and += on std::valarray<T>

我正在使用类型 std::valarray<std::valarray<double>> 并希望对每个包含的 valarrays 元素进行明智的求和,留下 std::valarray<double>.

C++ 文档指出,只要运算符 += 是为类型 T 定义的,运算符 .sum() 就可以应用于 std::valarray<T>。我下面的代码(方法 1)尝试应用这对 std::valarray<std::valarray<double>>,但结果似乎是胡说八道。

但是,如果我使用 += 运算符(方法 2)手动执行此操作,我会得到我想要的结果。但 method2 有效的事实似乎暗示运算符 += 是为类型 std::valarray<double> 定义的,因此 method1 使用 .sum()。应该管用。我真的不明白这里发生了什么......

我的代码:

#include <iostream>
#include <valarray>

// Attempt to use .sum() operator
std::valarray<double> method1(const std::valarray<std::valarray<double>>& data) {
  return data.sum();
}

// Manual summation using += operator
std::valarray<double> method2(const std::valarray<std::valarray<double>>& data) {
  std::valarray<double> sum(data[0].size());
  for (size_t i{0}; i < data.size(); i++) {
    sum += data[i];
  }
  return sum;
}

// Display size and elements
void showData(const std::valarray<double> data) {
  std::cout << "Size = " << data.size() << "\n";
  std::cout << "Data = ";
  for (size_t i{0}; i < data.size(); i++) {
    std::cout << data[i] << " ";
  }
  std::cout << "\n\n";
}

int main() {
  std::valarray<std::valarray<double>> data{{1,2},{3,4}};  
  showData(method1(data));
  showData(method2(data));
}

我的输出:

Size = 0
Data = 

Size = 2
Data = 4 6

std::valarraysum 方法要求为其值类型定义 operator+=(在您的情况下,std::valarray),但 std::valarray 也要求它是 default-constructible(来自 "Numeric" 概念要求)。 这允许 sum 方法在没有 operator+ 的情况下工作,首先 default-constructing 一个元素,然后添加每个包含的元素 operator+=.

虽然它没有在任何地方定义,但据我所知,它可能是这样工作的。

T sum() const {
    T result;
    for (auto& it : elements) {
        result += it;
    }
    return result;
}

valarray 的 valarray (std::valarray<std::valarray>) 的问题是 default-constructed valarray 是空的。当 operator+= 与一个空的 valarray 和一个 non-empty 一起应用时,它会导致未定义的行为 ("The behavior is undefined if size() != v.size()")。结果你可能会得到一个空的 valarray(但你可能会得到任何东西)。

您可以使用 std::accumulate。它需要一个初始值作为第三个参数,它解决了这个问题。

std::accumulate(std::begin(data), std::end(data), std::valarray<double>(data[0].size()))

Live on Coliru.

PS:别问我为什么std::valarray没有方法beginend.