I took a look at erase_tail_copy and it seems it's not exactly what I want. The erase_tail_copy is considered a mutating function in this library and therefor requires a SequenceT as an input, rather than a RangeT (no string literals allowed). It also makes a copy of the input string when I don't think there's any need to.
In other words, those erase_xxx_copy functions are, IMO, misplaced. No wonder I couldn't find them in the first place... I think they are essentially find algorithms just like the find_head/find_tail functions, and should: 1. Be named find_something, not erase_something 2. Placed in the find.hpp header, not erase.hpp 3. Accept RangeT (including string literals) 4. Return an iterator_range just like the find_xxx functions, without making copies (of course there could also be _copy versions, but on the other hand, do the find_xxx functions have _copy versions?).
The definition and placement of erase_tail_copy is consistent with other erase_xxx algorithms, it should not be changed.
BTW: find_xxx functions does not need to have copy variants, since they are not mutating algorithms. Find simply returns a reference to a input string. It is up to you what to do with it. One possility is to make a copy. In mutating algorithms like replace and erase, there is fundamental difference how algorithm behaves in mutable and copy version.
My point was that erase_tail_copy /can/, and therefor /should/, be defined in terms of 'find' rather than in terms of 'mutate'. The 'find' notions is prefered since it's not intrusive, and leave more control in the hands of the user. For this reason, anything that can be defined in 'find' terms, should be. On the other hand, if you really want to keep the mutating version of erase_tail_copy, then so be it. You won't here any more arguments from me... ;-)
erase_tail_copy does not exactly be what a find_head would. But it is quite close. The only serious diference is, that it does not return an iterator_range based reference to the input string, rather a copy of it. This might be a serious problem, however I have not yet come to a situation were it realy mattered. On the other hand, my personal experience does not prove anything globaly.
Therefore the only reasonable way to provide the exact functionality as you requested is to modify find_head (or add find_head_but). If we are going this way I'm biased to provide negative-index variant, due to similarities with scripting languages.
At the end, I feel, that it would do no wrong to extend find_head/tail and then probably also find_nth with the support for negative indexes. So, when I get a chance, I'll implenet it.
I have to say that I'm quite convinced that adding a new function is somewhat better then the negative numbers approach. It's true that the negative technique has some history in scripting languages, but I think we can do better in C++. But on this matter, as on the previous one, if you decide on the negative number approach, I'll argue no more. And btw, whatever method chosen to do it with find_head/find_tail, it should probably also be applied to erase_head/erase_tail[_copy]. These functions should also deal with 'backward' (negative) indices. Thanks again, Yuval