1

I have a simple usage of traversing a temporary std::valarray expression in range for loop, but got error: invalid range expression ...

main.cpp

#include <iostream>
#include <valarray>

int main()
{

    std::valarray<int> xxx {2,7,1,8,2,8};
    std::valarray<int> zzz {xxx};

    for (auto x : xxx + zzz) std::cout << x << std::endl;

    return 0;
}

clang++ main.cpp -std=c++11

main.cpp:10:17: error: invalid range expression of type 'std::__1::__val_expr<std::__1::_BinaryOp<std::__1::plus<int>, std::__1::valarray<int>, std::__1::valarray<int> > >'; no viable 'begin' function available
    for (auto x : xxx + zzz) std::cout << x << std::endl;
                ^ ~~~

Is there really a good reason that it does not compile as I expected? Return type of the overloaded operator+ is valarray<T>, so theoretically, value of the expression should be a temporary instance of type valarray<T>.

Synopsis:

template<class T> valarray<T> operator+ (const valarray<T>& x, const valarray<T>& y);

Version: Apple LLVM version 8.0.0 (clang-800.0.38) Target: x86_64-apple-darwin15.6.0

Note following line works

for (auto x : xxx += zzz) std::cout << x << std::end;
Lance LI
  • 113
  • 3
  • 9

4 Answers4

1

As a "begin" and "end" are available for the operator+ return type, namely valarray<T> I'd say the error is wrong and it should compile.

acraig5075
  • 10,588
  • 3
  • 31
  • 50
  • 1
    For some reasons gcc and and clang both return `std::_Expr, int>` instead of `std::valarray`. – Simon Kraemer Nov 11 '16 at 10:49
  • That's why I am asking ... vc++ can do it. – Lance LI Nov 11 '16 at 10:53
  • The return type of operator+ for valarrays is not required to be std::valarray (and I'd even say if it is std::valarray, the implementation is broken) – Cubbi Nov 28 '16 at 13:59
  • Is it not required? broken? why? could you please explain it better. because if you look at declaration, you will find it is indeed std::valarray ``template valarray operator+ (const valarray& x, const valarray& y);`` – Lance LI Nov 30 '16 at 08:09
0

What do you want to do? If you want to traverse xxx do the for only in it:

for (const auto x : xxx) std::cout << x << std::endl;

But answering the basics of your question, the expression (xxx + yyy) is not iterable. If you want to do the for loop in both, you do two fors:

for (auto x : xxx) std::cout << x << std::endl;
for (auto x : zzz) std::cout << x << std::endl;

If you want to do it in a single loop, you can append both

xxx += yyy;
for (auto x : xxx) std::cout << x << std::endl;

PD from edit: The line

for (auto x : xxx += yyy) std::cout << x << std::endl;

works because it makes the append first and then iterates. Is equivalent to my last suggestion. But (xxx+yyy) is not iterable.

From your comment: valrray::operator+(valarray) does not exist. valrray::operator+=(valarray) does exist.

LeDYoM
  • 949
  • 1
  • 6
  • 21
  • "expression (xxx + yyy) is not utterable" -- why? – Lance LI Nov 11 '16 at 10:26
  • @LanceLi the result of xxx+yyy is something that is not iterable. The operator + is different from operator+=. – LeDYoM Nov 11 '16 at 10:29
  • Take a look at http://en.cppreference.com/w/cpp/numeric/valarray operators like + do operations in a per element basis and += is appending the array. – LeDYoM Nov 11 '16 at 10:31
0

The range for loop uses the non-member std::begin and std::end, which are not required to exist for the return type of operator+ for std::valarray.

The portable syntax is

for(auto x : std::valarray<int>(xxx + zzz))

This is noted on cppreference and in the standard under 26.7.1[valarray.syn]p4.1

Cubbi
  • 46,567
  • 13
  • 103
  • 169
0

This is a really good question. The reason is the behavior of A+B over valarrays.

Let us see what I mean by this.

First, try these lines.

std::valarray<int> xxx {2,7,1,8,2,8};
std::valarray<int> zzz {xxx};
auto t=xxx+zzz;
cout<<typeid(t).name()<<endl;
cout<<typeid(xxx).name()<<endl;
cout<<typeid(xxx+zzz).name()<<endl;

you will notice that they are not the same, and this is due to the definition of the + operator here https://en.cppreference.com/w/cpp/numeric/valarray/operator_arith3 As it is written the type is deduced. This means that its behavior is similar to auto. The question then is why does it not deduce the same type, valarray. Probably, it is due to a compiler optimization feature, or maybe it is a mistake, but it is clear that the reference does not force the compiler to deduce the same type. The thing is the deduced type happens to be not iterable by a range based for loop.

Please let me know if anything is not clear.

Motaz Hammouda
  • 122
  • 1
  • 9