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

寵の児 提交于 2020-01-13 07:53:07

问题


Consider the following MCVE, where I have two value arrays where w is two times v (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
}

This example fails to compile with clang and gcc at the last loop with (gcc output here):

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

The source of the problem seems to be the decuced type of v * 2 (I assume that because explicitly writing down the type works, so some implicit conversion seems to be taking place).

Looking at the reference notes, it seems that operator* may return something different than std::valarray<T>. I don't understand the reason for this but more puzzling is that the same seem to apply to operator*=, except that here my auto assignment works. I would expect the return values of operator*= and operator* to be the same here (delta the reference).

So my questions are:

  • Is this an implementation issue/bug? Or am I missing something?
  • What's the rationale behind the reference notes (e.g. why can the operators return something different that may not work with std::begin/std::end)?

(Note: I tagged this question c++11, but it seems to apply to all versions up to 17 as well)


回答1:


There is a trick called expression templates that permit efficiencies in compound expressions, but break horribly with use of auto.

Change this:

auto w = v * 2;

to this:

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

and your code works.


To see why we want to use expression templates, try this:

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

here the expression templates avoid creating a temporary valarray a+b*2 or b*2, but instead pass the entire expression down, and construct r with element-wise operations.

No 3-element valarray temporaries are created in (a+b*2)*c -- just a series of objects that describe the expression structure and arguments. When assigned to an actual valarray the expression is then evaluated on an element-by-element basis.

But auto doesn't convert to valarray; it just stores the expression template object. So your code breaks.

I don't know which versions of the standard permit this or not; regardless, some valarray implementations use this, and it adds a lot of efficiency. Without it, valarray frankly sucks.



来源:https://stackoverflow.com/questions/56222576/whats-wrong-with-stdvalarrays-operator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!