Why do you need a std function:advance, next, prev?



  • Standard library C+++ has functions std::advancestd::nextstd::prev
    Why do they need them and where should they be used?



  • Function std::advance previous functions std::next and std::prev still in C++ 2003, while the last two functions appeared in the standard C++ 2011

    Function std::advance has the following announcement:

    template <class InputIterator, class Distance>
    void advance(InputIterator& i, Distance n);
    

    As can be seen from the announcement, the function changes the terator that has been referred to it as the first parameter.

    However, practice has shown that it is very often necessary to create a new terator that is pre-emptive or later relative to the current iterator. In this case, I have had to resort to a pseudo code (I use the term pseudo code, because I use the key word in it. autowhich, in C+ 2003, had not yet been the same as in C+ 2011 because, in the general case, iterators, with the exception of arbitrary access, did not have a combination of wholesale transactions:

    auto next = current;
    advance( next, n );
    

    where n - a certain number.

    For example, we consider finding a maximum element in the second half of the elements of a list.

    #include <list>
    #include <algorithm>
    #include <iterator>
    

    // ...

    std::list<int> lst;

    // инициализация списка некоторыми значениями

    std::list<int>::iterator it = lst.begin();
    std::advance( it, lst.size() / 2 );

    it = std::max_element( it, lst.end() );

    As a function std::advance Type of return voidand she's changing her source as an argument, she's uncomfortable with algorithms. Additional announcements and code proposals are required to trigger an algorithm. Like, that's what the algorithm could look like. std::rotate for the list using the function std::advance

    #include <list>
    #include <algorithm>
    #include <iterator>

    // ...

    std::list<int> lst;

    // инициализация списка некоторыми значениями

    std::list<int>::iterator middle = lst.begin();
    std::advance( middle, lst.size() / 2 );
    std::rotate( lst.begin(), middle, lst.end() );

    In addition, the word advance Not quite successful when it comes to the calculation of the terators that precede the intended terator. In this case, it is necessary to indicate a negative value for the second argument of the function, which may be a source of error. For example,

    std::advance( middle, -1 );

    It is difficult to conclude from this proposal whether -1 It is indeed the intention of the programmer.

    Names like prev or next More clearly express the intentions of the programmer and make the code more readable.

    It was therefore suggested that the functions should be introduced. std::prev and std::next in standard C++ 2011. Moreover, these functions are being returned by the terator, and they can be built into algorithms. They do not alter the iterators, on the basis of which the functions are being returned by new heterans.

    Previous example of algorithm challenge std::rotate for the list now using these functions, one line may be added

    #include <list>
    #include <algorithm>
    #include <iterator>

    // ...

    std::list<int> lst;

    // инициализация списка некоторыми значениями

    std::rotate( lst.begin(), std::next( lst.begin(), lst.size() / 2 ), lst.end() );

    I mean, new iters or phrases with summer terators can be obtained without blocking the code for the announcements of intermediate variables that are required only to calculate algorithm arguments.

    Iterators of arbitrary access can be folded with numerous expressions to obtain a new terator. For example,

    std::vector<int> sequence = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    std::rotate( sequence.begin(), sequence.begin() + sequence.size() / 2, sequence.end() );

    However, this code is not flexible. If for any reason you want to use another container that doesn't have arbitrary access, you're gonna have to change the algorithm proposal.

    It would be much better if, even for the arbitrary access harbours, you would use the common functions.

    std::vector<int> sequence = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    std::rotate( sequence.begin(), std::next( sequence.begin(), sequence.size() / 2 ), sequence.end() );

    Especially these functions are irreplaceable when you write a template code for an arbitrary type of heteros.

    Both functions std::next and std::prev have a default argument for the second parameter:

    template <class ForwardIterator>
    ForwardIterator next(ForwardIterator x,
    typename std::iterator_traits<ForwardIterator>::difference_type n = 1);

    template <class BidirectionalIterator>
    BidirectionalIterator prev(BidirectionalIterator x,
    typename std::iterator_traits<BidirectionalIterator>::difference_type n = 1);

    These functions are therefore very convenient when the next or previous terator is required. For example,

    std::vector<int> v = { /* некоторые значения */ };

    auto after_first = std::next( v.begin() );
    auto before_last = std::prev( v.end() );

    It would be logical for a function std::advance also had a default argument for the second parameter. Then instead of expression, like,

    auto it = v.begin();
    std::advance( it, 1 );

    You could write it down easier.

    auto it = v.begin();
    std::advance( it );

    And the word advance in this case would correspond to its direct meaning.

    I have made such a proposal to include a function in the declaration std::advance value of the argument for default 1 for the second performance.

    With my proposal to change C++ with regard to the function std::advance click here http://cpp.forum24.ru/?1-3-0-00000076-000-0-0-1423215180




Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2