glibcxx STL 在 std::valarray::sum() 的实现中是否不正确?
Is the glibcxx STL incorrect in its implementation of std::valarray::sum()?
我正在玩 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 上复制的,可能 运行ning 在 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();
,他们生成了一个 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;
}
我正在玩 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 上复制的,可能 运行ning 在 cygwin 下...
这对我来说是个错误。 sum()
Requires:
size() > 0
. This function may only be instantiated for a typeT
to whichoperator+=
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();
,他们生成了一个 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;
}