glibcxx STL在实现std :: valarray :: sum()时是否不正确?

时间:2018-10-17 18:37:47

标签: 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;

     

此功能只能在类型为T的情况下实例化   可以应用哪个运算符+ =。此函数返回所有的总和   数组的元素。如果数组的长度为0,则行为   未定义。如果数组的长度为1,sum()返回的值为   元素0。否则,返回值通过应用   运算符+ =到数组元素和所有其他元素的副本   数组的顺序不确定。

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下运行...

1 个答案:

答案 0 :(得分:5)

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

  

要求: size() > 0。只能为可以应用T的类型operator+=实例化此功能。

valarray确实有operator +=,因此符合条件。是operator +=

  

要求: size() == v.size()。如果指定的运算符可以应用于类型T的两个操作数,则只能为类型T实例化每个运算符。valarray复合赋值运算符左侧的元素值不依赖于左侧的另一个元素。

因此,通过执行_Tp __r = _Tp();,它们会生成一个valarray,其size()不等于元素的大小,因此无法与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;
    }