Is there an elegant way to pass a subset of one deque to another?

Is boost possible or otherwise?

I want to create a function to capture a subset of deque d from (and including) the iStart index at index 0 in the new deque, but also set that these values โ€‹โ€‹in d are 0. I thought about this:

 std::deque<int> CreateSubset(std::deque<int>& d, int iStart ) { int iSubsetSize = iStart+1; std::deque<int> subset(iSubsetSize); // initialise a deque of a certain size. std::deque<int>::iterator it = d.begin(); subset.assign (it, d.begin()+iStart+1); for(;it != d.begin()+iStart+2; it++) { *it = 0; } return subset; } 

But it looks awful to me - is there a better way?

+4
source share
2 answers

This is how I would do it in C ++ 11. I think the code is pretty neat and I donโ€™t think there is anything particularly inefficient in it:

 #include <iostream> #include <deque> #include <iterator> #include <algorithm> template <typename ForwardIt> std::deque<int> extract(ForwardIt from, ForwardIt to) { using std::make_move_iterator; std::deque<int> d2(make_move_iterator(from), make_move_iterator(to)); std::fill(from,to,0); return d2; } 

The extract() function template takes two iterators forward, moves the contents between them to the newly created deque, and sets it to 0 in the original.

In the written template, two assumptions are made:

  • Although the source iterators may refer to something, the destination is always deque;
  • The default value for resetting the source elements is 0.

Both assumptions can be mitigated by introducing additional template parameters or function arguments.

As you can see, I use std::make_move_iterator to convert input iterators to move iterators, which causes the elements to move (rather than copy) to the destination. As long as they are int , it really doesn't matter.

I use the std::fill algorithm to set the source elements to 0.

Here is how you could call this function template:

 int main() { /* Creating d. */ std::deque<int> d { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; /* Extracting the first three elements into a new deque. */ auto d2 = extract(begin(d),begin(d) + 3); /* Printing the results. */ std::cout << "d:\n"; for (const auto &elem : d) std::cout << elem << ','; std::cout << "\n\nd2:\n"; for (const auto &elem : d2) std::cout << elem << ','; std::cout << std::endl; return 0; } 
+7
source

Since the concept of a container requires container types to define iterator and const_reference , it is even possible that jogojapan will respond a little more generically without having more than one template parameter.

 template <typename Container> Container extract(typename Container::iterator from, typename Container::iterator to, typename Container::const_reference replacement) { using std::make_move_iterator, std::fill; Container new_container(make_move_iterator(from), make_move_iterator(to)); fill(from,to,replacement); return new_container; } 

Where can you go

 deque<int> d { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; auto d2 = extract<deque<int>>(begin(d),begin(d) + 3, 0); 

The downside is that the template argument output will no longer work.

The advantage is that you can use the code for almost all STL containers, such as vectors, deque, list, forward_list, set, map ... since they all have at least forward_iterator as their type of iterator. You can also specify a default replacement.

You can also use a pointer instead of a link so that you can decide whether you want to delete (pass nullptr) or replace the elements with a specific value (passing a valid pointer to the corresponding object).

+3
source

Source: https://habr.com/ru/post/1487717/


All Articles