std::valarray 的 operator* 有什么问题?

What's wrong with std::valarray's operator*?

考虑以下 MCVE,其中我有两个值数组,其中 wv 的两倍(try it out here):

#include <valarray>

using namespace std;

int main() {
  valarray<int> v { 1, 2, 3 };

  for ([[maybe_unused]] auto x : v) {} // Ok

  auto w = v * 2;     // Leads to failure in loop below
  //valarray<int> w = v * 2; // Works
  //auto w = v*=2;      // Works
  //auto w = v; w *= 2; // Works

  for ([[maybe_unused]] auto x : w) {} // Failure here
}

此示例在最后一个循环中使用 clang 和 gcc 编译失败(此处为 gcc 输出):

error: no matching function for call to 'begin(std::_Expr<std::__detail::_BinClos<std::__multiplies, std::_ValArray, std::_Constant, int, int>, int>&)'

问题的根源似乎是 v * 2 的 decuced 类型(我假设因为显式写下类型有效,所以似乎发生了一些隐式转换)。

查看 reference notes,似乎 operator* 可能 return 与 std::valarray<T> 有所不同。 我不明白这样做的原因,但更令人费解的是 the same seem to apply to operator*=,除了这里我的 auto 作业有效。我希望 operator*=operator* 的 return 值在这里相同(增量参考)。

所以我的问题是:

(注意:我将这个问题标记为 c++11,但它似乎也适用于 17 及以下的所有版本)

有一个称为表达式模板的技巧可以提高复合表达式的效率,但会严重破坏 auto

改变这个:

auto w = v * 2;

对此:

std::valarray<int> w = v * 2;

并且您的代码有效。


要了解我们为什么要使用表达式模板,试试这个:

std::valarray<int> a={1,2,3},b{4,5,6},c={2,4,8};
std::valarray<int> r = (a+b*2)*c;

此处的表达式模板避免创建临时的 valarray a+b*2b*2,而是将整个表达式向下传递,并使用 element-wise 操作构造 r

(a+b*2)*c 中没有创建 3 元素 valarray 临时对象——只是一系列描述表达式结构和参数的对象。当分配给实际的 valarray 时,表达式将在 element-by-element 基础上计算。

但是 auto 没有转换为 valarray;它只存储表达式模板对象。所以你的代码中断了。

我不知道哪个版本的标准允许这样做;不管怎样,一些 valarray 实现使用它,它增加了很多效率。没有它,valarray 坦率地说很烂。