c++ - glibcxx STL 在其 std::valarray::sum() 的实现中是否不正确?

标签 c++ gcc valarray

我在玩弄valarrays当我碰到某些东西时,我认为是编译器的 STL 实现中的错误。这是我可以制作的最小示例:

#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
#include <valarray>

using namespace std;

int main()
{
    valarray<int> Y(0xf00d, 1);
    valarray<valarray<int>> X(Y, 1);
    cout << "Y[0]           = " << std::hex << Y[0]       << '\n';
    cout << "X[0][0]        = " << std::hex << X[0][0]    << '\n';
    cout << "X[0].size()    = " << X[0].size()            << '\n';
    cout << "X.sum().size() = " << X.sum().size()         << '\n';
}

这将输出:

$ g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Y[0]           = f00d
X[0][0]        = f00d
X[0].size()    = 1
X.sum().size() = 0

您可以在coliru 编译并运行它

为什么我认为这是一个错误?因为按照标准(26.6.2.8)

T sum() const;

This function may only be instantiated for a type T to which operator+= can be applied. This function returns the sum of all the elements of the array. If the array has length 0, the behavior is undefined. If the array has length 1, sum() returns the value of element 0. Otherwise, the returned value is calculated by applying operator+= to a copy of an element of the array and all other elements of the array in an unspecified order.

valarray 确实有一个 += operator

所以我希望 X.sum()X[0] 具有相同的值。但显然不是这样,因为它的大小是 0 而不是 1。

我查看了 sum() 的实现并将其追溯到这段代码:

  //
  // Compute the sum of elements in range [__f, __l)
  // This is a naive algorithm.  It suffers from cancelling.
  // In the future try to specialize
  // for _Tp = float, double, long double using a more accurate
  // algorithm.
  //
  template<typename _Tp>
    inline _Tp
    __valarray_sum(const _Tp* __f, const _Tp* __l)
    {
      _Tp __r = _Tp();
      while (__f != __l)
        __r += *__f++;
      return __r;
    }

我们知道问题出在哪里。代码将总和累加到 __r 中,但不是用 valarray 中的第一项初始化 __r,而是默认构造它。 valarray 的默认构造函数创建一个大小为 0 的数组。因此最终结果仍然是一个大小为 0 的 valarray。

我对标准的理解是否有效(并且 glibcxx STL 有错误)?还是应该纠正?

郑重声明,我在 cygwin 下使用 g++ 7.3.0,但它是在 coliru 上复制的,它可能没有在 cygwin 下运行...

最佳答案

这对我来说是一个错误。 sum()

Requires: size() > 0. This function may only be instantiated for a type T to which operator+= can be applied.

valarray 确实有一个 operator += 所以它符合条件。这是operator +=

Requires: size() == v.size(). Each of these operators may only be instantiated for a type T if the indicated operator can be applied to two operands of type T. The value of an element in the left-hand side of a valarray compound assignment operator does not depend on the value of another element in that left hand side.

所以通过执行 _Tp __r = _Tp(); 他们生成一个 valarraysize() 不等于元素的大小因此它不能与它的 operator += 一起使用。更正确的实现方式是

  template<typename _Tp>
    inline _Tp
    __valarray_sum(const _Tp* __f, const _Tp* __l)
    {
      _Tp __r = *__f++; // this is okay as the function is requires size > 0.  It is the users responsibility to make sure that is the case
      while (__f != __l)
        __r += *__f++;
      return __r;
    }

关于c++ - glibcxx STL 在其 std::valarray::sum() 的实现中是否不正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52861540/

相关文章:

c++ - 是否可以向 C++ 用户定义的文字运算符传递空指针?

c++ - 在哪里使用 "std::valarray"是个好主意?

c++ - resize 是否保证 std::valarray 归零?

c++ - 在 Codegear RAD Studio 中缩进

c++ - 如何将字符数组复制到剪贴板?

gcc - MacOS High Sierra上的链接错误: “Undefined symbols for architecture x86_64” std::__1

c++ - 将原始指针提升到 valarray

c++ - 通过qt中的打印机设备打印pdf文件

c++ - For 循环中的 Switch 语句无法检查特定值的变量

c - 属性构造函数样式函数的参数