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:
std::begin
/std::end
)?(Note: I tagged this question c++11, but it seems to apply to all versions up to 17 as well)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With