我正在玩弄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() 常量;
该函数只能为类型 T 实例化
可以应用哪个运算符+=。该函数返回所有的总和
数组的元素。如果数组的长度为 0,则行为
未定义。如果数组长度为 1,sum() 返回的值
元素 0。否则,返回值通过应用计算
运算符+= 到数组的一个元素和所有其他元素的副本
以未指定的顺序排列数组。
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
valarray 中的第一项是默认构造的。 valarray 的默认构造函数创建一个大小为 0 的数组。因此最终结果仍然是一个大小为 0 的 valarray。
我对标准的理解是否有效(glibcxx STL 有一个错误)?或者我应该被纠正?
作为记录,我在 cygwin 下使用 g++ 7.3.0,但它是在 coliru 上复制的,它可能不在 cygwin 下运行...