gcc 中的 std::valarray 实现存在 bug 吗?

4

我尝试了以下程序

#include <iostream>
#include <valarray>

int main( void ) 
{
    std::valarray<int> v1 = { 1, 2, 3, 4, 5 };
    std::valarray<int> v2 = { 1, 2, 3, 4, 5 };

    auto v3 = v1 * v2;

    for ( const auto &item : v3 ) std::cout << item << ' ';
    std::cout << '\n';

    return 0;
}

我得到了一个错误消息,该语句中隐式使用了v3的适当函数begin

    for ( const auto &item : v3 ) std::cout << item << ' ';

无法找到。

因此,我尝试了以下代码

#include <iostream>
#include <valarray>
#include <type_traits>

int main( void ) 
{
    std::valarray<int> v1 = { 1, 2, 3, 4, 5 };
    std::valarray<int> v2 = { 1, 2, 3, 4, 5 };

    auto v3 = v1 * v2;

    std::cout << std::is_same<std::valarray<int>, decltype( v3 )>::value << '\n';
    return 0;
}

并获得了结果。
0

但是,当这个声明

auto v3 = v1 * v2;

被更改为

std::valarray<int> v3 = v1 * v2;

那么输出结果是:

1

std::valarray<int>operator * 声明如下

template<class T> valarray<T> operator* (const valarray<T>&, const valarray<T>&);

那么这是 std::valarray<int> 实现的一个 bug 吗?

如果您将 auto v3 = ... 替换为 std::valarray<int> v3 = ...,则代码将按预期编译和运行。通过使用 autov3 是一些中间表达式模板生成的类型。 - Praetorian
1
valarray 上的运算符允许返回代理对象,这使得实现可以将多个操作(如 a * b + c)优化为单个循环。我不知道代理对象是否需要实现 begin()end() - interjay
请参见http://eel.is/c++draft/valarray.syn#3.sentence-1,这意味着您不允许使用`auto`并对其进行测试的期望。 - Kerrek SB
1个回答

5
这不是一个 bug。std::valarray::operator* 不必实际返回 std::valarray,因为它允许使用表达式模板。这意味着它可以返回具有以下属性的类型:
- 提供了 std::valarray 的所有 const 成员函数。 - 可以从替换类型构造 std::valarray、std::slice_array、std::gslice_array、std::mask_array 和 std::indirect_array。 - 所有接受 const std::valarray& 类型参数的函数(自 C++11 起除外 begin() 和 end())也应该接受替换类型。 - 所有接受两个 const std::valarray& 类型参数的函数应该接受任何 const std::valarray& 和替换类型的组合。 - 返回类型在最深嵌套的参数类型上不添加超过两层的模板嵌套。

我加粗了重点 来源

因此,您需要明确地将返回值捕获为 std::valarray,以便可以调用 std::begin 的特化版本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接