Passing to a Reference Argument by Value

泄露秘密 提交于 2019-12-01 15:20:23
thorsan

A solution could be as follows (even though you are making a temporary)

template<class T>
void replace_value_of_first(std::vector<T>& v, const T& value)
{
    std::replace(v.begin(), v.end(), T(v.front()), value);
}

You can write a simple function that takes in a reference and returns a value. this will "convert" the reference into a value. This does generate a temporary but it is unnamed and will be destroyed at the end of the full expression. Something like

template<typename T>
T value(const T& ref)
{
    return ref;
}

And then you can use it like

int main()                                                   
{                                                            
    vector<int> foo = {0, 42, 0, 42, 0, 42};
    replace(begin(foo), end(foo), value(foo.front()), 13);

    for(const auto& i : foo) cout << i << '\t';                                      
}

output:

13  42  13  42  13  42

Live Example

You can convert the given value into an rvalue to achieve the desired effect. The example below works, without defining any extra functions, simply by adding zero to the value.

vector<int> foo = {0, 42, 0, 42, 0, 42};
replace(begin(foo), end(foo), foo.front()+0, 13);

for(const auto& i : foo) cout << i << '\t';

Or even (as suggested by Jarod42) just the unary + operator, which is a no-op:

vector<int> foo = {0, 42, 0, 42, 0, 42};
replace(begin(foo), end(foo), +foo.front(), 13);

for(const auto& i : foo) cout << i << '\t';

Obviously either of these still create a temporary. I don't think you can get away from that.

In this particular case (when the old value is the first of the vector), you can reverse the order of substitution with rbegin() and rend().

In general, I don't know if it's possible, in a simple way, without make a copy.

int main ()
 {
   std::vector<int> foo = {0, 42, 0, 42, 0, 42};
   std::replace(foo.rbegin(), foo.rend(), foo.front(), 13);

   for(const auto & i : foo)
      std::cout << i << '\t';

   std::cout << std::endl;

   return 0;
 }

p.s.: sorry for my bad English.

To be more explicit you can use int() as a constructor to create a temporary:

replace(begin(foo), end(foo), int(foo.front()), 13);

Instead of adding a value. See Demo.

One liner that should work for any type, not only numeric:

replace(begin(foo), end(foo), make_pair(foo.front(),0).first, 13);

or without creating extra field:

replace(begin(foo), end(foo), get<0>( make_tuple(foo.front()) ), 13);
vector<int> foo = {0, 42, 0, 42, 0, 42};
replace(begin(foo), end(foo), static_cast<int>(foo.front()), 13);
assert(equal(begin(foo), end(foo), begin({13, 42, 13, 42, 13, 42})));
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!