Gladaed
Gladaed

Reputation: 211

std::transform with std::reference_wrapper

How do you use std::transform in conjunction with containers which hold objects of type std::reference_wrapper? when reading from const std::vector<std::reference_wrapper<const float>> and writing into an std::vector<float> everything works, but if I try to write into an std::vector<std::reference_wrapper<float>> it doesn't compile giving the error

/usr/include/c++/5/bits/stl_algo.h:4214: error: use of deleted function >'std::reference_wrapper<_Tp>::reference_wrapper(_Tp&&) [with _Tp = float]' __result = __binary_op(__first1, *__first2);

I think it is trying to replace the reference instead of changing the value of the referred value. Is there a way to use transform to achieve this or should I prefer writing my own function?

edit: added a example for reference:

#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>

int main()
{
std::vector<float> v(3, 1.0f);
std::vector<std::reference_wrapper<float>> refVector;

refVector.reserve(v.size());
for(auto& elem : v)
{
refVector.push_back((std::reference_wrapper<float>)elem);
}

std::vector<float> v2(3, 2.0f);
std::vector<float> v3(3, 3.0f);
std::vector<float> v4(3);

for(auto& elem : v)
std::cout << elem << std::endl; // all 1s

std::transform(refVector.begin(), refVector.end(), v3.begin(), v4.begin(), std::plus<float>());

for(auto& elem : v4)
std::cout << elem << std::endl; // all 4s

std::transform(v2.begin(), v2.end(), v3.begin(), refVector.begin(), std::minus<float>()); // doesn't compile

for(auto& elem : v)
std::cout << elem << std::endl; // want all -1s

return 0;
}

Upvotes: 0

Views: 928

Answers (1)

Caleth
Caleth

Reputation: 62864

If you are trying to overwrite existing floats that are referenced in your std::vector<std::reference_wrapper<float>>, then you need something that will unwrap the std::reference_wrapper<float> into a float &. boost::indirect_iterator is such a thing, although it is easy to write your own iterator adapter if you can't add a boost dependancy.

An example usage:

std::vector<float> src1 = /* values */, src2 = /* other values */;
std::vector<std::reference_wrapper<float>> dest = /* references to somewhere */;

boost::indirect_iterator<std::reference_wrapper<float>, float> indirected(dest.begin());
std::transform(src1.begin(), src1.end(), src2.begin(), indirected, std::plus<float>());

A sketch implementation

struct indirect_iterator
{
    /* a bunch of typedefs go here */
    indirect_iterator& operator++() { ++inner; }
    float & operator*() { return inner->get(); }
    float * operator->() { return &inner->get(); }  
private:
    std::vector<std::reference_wrapper<float>>::iterator inner;
} 

Upvotes: 1

Related Questions