std :: valarray的运算符*有什么问题?

and*_*eee 11 c++ operators language-lawyer c++11 valarray

考虑下面的MCVE,其中有两个值数组,其中w两次是两次v在此处尝试):

#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
}
Run Code Online (Sandbox Code Playgroud)

这个例子在最后一个循环中用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>&)'
Run Code Online (Sandbox Code Playgroud)

问题的根源似乎是减少的类型v * 2(我假设因为显式地记录了该类型有效,所以似乎正在进行一些隐式转换)。

查看参考注释,似乎operator*返回的内容与std::valarray<T>。我不明白这样做的原因,但更令人困惑的是,这似乎适用于operator*=,除了我的auto作业在这里起作用。我期望的返回值operator*=,并operator*以相同这里(增量参考)。

所以我的问题是:

  • 这是实现问题/错误吗?还是我错过了什么?
  • 参考说明背后的原理是什么(例如,为什么操作员可以返回可能不适用于std::begin/的其他内容std::end)?

(注意:我标记了这个问题c ++ 11,但它似乎也适用于所有版本,最高为17)

Yak*_*ont 13

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

更改此:

auto w = v * 2;
Run Code Online (Sandbox Code Playgroud)

对此:

std::valarray<int> w = v * 2;
Run Code Online (Sandbox Code Playgroud)

并且您的代码有效。


要了解为什么我们要使用表达式模板,请尝试以下操作:

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

在这里,表达式模板避免创建临时的valarray a+b*2b*2,而是向下传递整个表达式,并r使用逐个元素的操作进行构造。

不会创建3元素的valarray临时(a+b*2)*c对象,而只是创建描述表达式结构和参数的一系列对象。当将其分配给实际valarray表达式时,将在逐个元素的基础上对表达式进行求值。

但是auto不会转换为valarray; 它只存储表达式模板对象。因此,您的代码会中断。

我不知道该标准的哪个版本允许这样做;不管怎样,某些valarray实现使用此方法,并且它增加了很多效率。没有它,valarray会很烂。

  • @marek也许不是,也不容易;返回真正有用的非输入迭代器的开始和结束,在Rangesv3之前需要后备容器。也许Rangesv3在这里可以找到一个很好的解决方案。 (2认同)