Setting std::vector elements according to a std::vector of indexes

Nov 18, 2016 at 1:00pm
Hi People,

I want to do -in the best possible way- something like this python line, in c++ by means of std::vector

v1[v2] = 1

That is: v1 elements are set to 1 taking into account v2 elements as indexes for v1.

Where v1 is a valarray of float elements and v2 is a vector of unsigned int elements, (v1 is initialized to 0 in every element).

If I cast v2 from std::vector<unsigned int> to std::valarray<unsigned int> I get the following error:

error: no match for 'operator[]' (operand types are 'std::valarray<float>' and 'std::valarray<unsigned int>')


in the line v1[v2] = 1.

This is the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <valarray>
#include <iostream>

int main()
{
    std::valarray<float> v1 = {0,0,0,0,0,0,0,0,0};
    std::vector<unsigned int> v = {0,2,4,6,8};

    std::valarray<unsigned int> v2(v.data(),v.size());

    v1[v2] = 1; // <-- this is the key line

    for(double d : v1) std::cout << d << ' ';

    return 0;    
}


On the other hand, when I try to cast v from std::vector<unsigned int> to std::valarray<size_t>:
(I do this because the line v1[v2] = 1; works fine when v2 is a std::valarray<long unsigned int>, I don't know why)
I get the following error:
error: invalid conversion from 'unsigned int*' to 'long unsigned int' [-fpermissive]

in the conversion line.
This is the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <valarray>
#include <iostream>

int main()
{
    std::valarray<float> v1 = {0,0,0,0,0,0,0,0,0};
    std::vector<unsigned int> v = {0,2,4,6,8};

    std::valarray<size_t> v2(v.data(),v.size());

    v1[v2] = 1;

    for(double d : v1) std::cout << d << ' ';

    return 0;    
}


Cubbi kindly replied a very fresh topic related to this one in:

http://www.cplusplus.com/forum/general/202649/

Thanks
Nov 18, 2016 at 1:45pm
std::size_t need not necessarily be an alias for unsigned int.
In this implementation, it is an alias for unsigned long

This would work everywhere:
1
2
3
4
5
6
7
std::valarray<float> v1 = {0,0,0,0,0,0,0,0,0};

// std::vector<unsigned int> v = {0,2,4,6,8};
std::vector<std::size_t> v = {0,2,4,6,8};

std::valarray<std::size_t> v2( v.data(), v.size() );
v1[v2] = 1;

Last edited on Nov 18, 2016 at 1:46pm
Nov 18, 2016 at 9:07pm
Thanks JLBorges,

I know that std::size_t is an alias for long unsigned int in this implementation.
Yet, this does not give me a solution.
All I need is to cast from std::vector<unsigned int> to std::valarray<long unsigned int>.
I need this conversion because in the line v1[v2] = 1;, v2 has to be a
std::valarray<long unsigned int> in order to work properly.

Perhaps it is important to point out that v2 is a function parameter which brings the std::vector<unsigned int> type.

Thanks
Nov 18, 2016 at 11:52pm
> All I need is to cast from std::vector<unsigned int> to std::valarray<long unsigned int>

cast from std::vector<unsigned int> to std::valarray<std::size_t>

Write a function which performs the type conversion:
1
2
3
4
5
6
7
8
9
template < typename T >
std::valarray<std::size_t> indirect_array( const std::vector<T>& vec )
{
    static_assert( std::is_integral<T>::value, "expected an integral type" ) ;

    std::valarray<std::size_t> result( vec.size() ) ;
    for( std::size_t i = 0 ; i < vec.size() ; ++i ) result[i] = vec[i] ;
    return result ;
}


And then:
1
2
3
4
5
6
7
8
void foo( std::valarray<float>& v1, const std::vector<unsigned int>& v2 )
{
    const auto v3 = indirect_array(v2);
    v1[v3] = 1 ;

    // or just
    v1[ indirect_array(v2) ] = 1 ;
}
Nov 19, 2016 at 11:17am
Thanks JLBorges!

I thought there was a prefabricated way to do the conversion.
I just didn't want to reinvent the wheel.
I tested the template and it works perfectly.
Thank you very much JLBorges.

Best,

Dario
Topic archived. No new replies allowed.