当我遇到我认为编译器的 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() 常量;
此函数只能为可以应用 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
使用 valarray 中的第一项进行初始化,而是默认构造。valarray 的默认构造函数创建一个大小为 0 的数组。所以最终结果仍然是一个大小为 0 的 valarray。
我对标准的理解是否有效(并且 glibcxx STL 有错误)?还是我应该纠正?
作为记录,我在cygwin下使用g ++ 7.3.0,但它是在coliru上复制的,它可能没有在cygwin下运行......