Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ range-based for loop over valarray rvalue is not working

I would like to iterate over a temporary valarray, but it isn't working. Here is my (non-working) code:

#include <iostream>
#include <valarray>
int main()
{
        using namespace std;
        valarray<int> numerators = {99, 26, 25};
        valarray<int> denominators = {9, 2, 5};
        for (int i : numerators / denominators) { cout <<  i << ","; }
        // lots of errors
        return 0;
}

Below is a minimal working example of what I would like to achieve, except that I don't want to define an object like temp_array.

#include <iostream>
#include <valarray>
int main()
{
        using namespace std;
        valarray<int> numerators = {99, 26, 25};
        valarray<int> denominators = {9, 2, 5};
        valarray<int> && temp_array = numerators / denominators;
        for (int i : temp_array) { cout << i << ","; }
        // prints 11,13,5,
        return 0;
}

My compiler is g++ version 4.8.5 (Red Hat 4.8.5-4). I am compiling with the -std=c++0x flag.

I've tried other syntax such as for (auto&& i : temp_array) and for (int const & i : temp_array), but it doesn't work.

like image 253
Jasha Avatar asked Jan 28 '16 16:01

Jasha


3 Answers

From the documentation (which also includes the official way to do this in a single expression):

Unlike other functions that take std::valarray arguments, begin() cannot accept the replacement types (such as the types produced by expression templates) that may be returned from expressions involving valarrays: std::begin(v1 + v2) is not portable, std::begin(std::valarray(v1 + v2)) has to be used instead.

The intent of this function is to allow range for loops to work with valarrays, not to provide container semantics.

As to what might be the reason, there's also this (which was pointed out by @chris):

[arithmetic operators] can be implemented with the return type different from std::valarray.

So there's technically nothing to guarantee that what returns can safely be passed on to std::begin.

like image 97
Yam Marcovic Avatar answered Nov 20 '22 21:11

Yam Marcovic


As pointed out in @Yam Marcovivc's answer the operation result isn't guaranteed to be a std::valarray<int> that can be passed directly to std::begin(). A temporary constructed object does the trick:

#include <iostream>
#include <valarray>
int main()
{
        using namespace std;
        valarray<int> numerators = {99, 26, 25};
        valarray<int> denominators = {9, 2, 5};
        for (int i : valarray<int>(numerators / denominators)) { 
            cout <<  i << ","; 
        }
        return 0;
}

See a Live Demo

like image 21
πάντα ῥεῖ Avatar answered Nov 20 '22 23:11

πάντα ῥεῖ


    for (int i : (valarray<int> &&)(numerators / denominators)) { cout << i << ","; }
like image 3
0xFFFFFFFF Avatar answered Nov 20 '22 21:11

0xFFFFFFFF