[英]Is the glibcxx STL incorrect in its implementation of std::valarray::sum()?
当我遇到一些我认为是编译器STL实现中的错误时,我正在玩valarrays 。 这是我可以生成的最小的例子:
#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;
此函数只能针对可应用operator + =的类型T进行实例化。 此函数返回数组的所有元素的总和。 如果数组的长度为0,则行为未定义。 如果数组的长度为1,则sum()返回元素0的值。否则,通过将operator + =应用于数组元素的副本以及数组中所有其他元素的未指定顺序来计算返回值。
valarray确实有一个+ =运算符
所以我希望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
,但不是使用__r
中的第一个项初始化__r,而是默认构造。 valarray的默认构造函数创建一个大小为0的数组。因此最终结果仍然是大小为0的valarray。
我对标准的理解是否有效(和glibcxx STL有错误)? 或者我应该纠正?
为了记录,我在cygwin下使用g ++ 7.3.0,但它在coliru上复制,可能不在cygwin下运行...
这对我来说是个错误。 sum()
要求:
size() > 0
。 此函数只能针对可应用operator+=
的类型T
进行实例化。
和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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.