Search code examples
c++type-conversionconst-iterator

casting a returned iterator to const


I have the following for statement in my code:

for (auto Iter = Target.begin(), 
        IterEnd = std::stable_partition(Target.begin(), Target.end(), Check);
    Iter != IterEnd; ++Iter)
    { /* loop statement */ }

The point is that the loop doesn't modify elements of the container, so it would make sense to declare iterators as const_iterator. I can easily solve the problem for the first using cbegin(), but the second is more complex. I can't declare cbegin() and cend() inside stable_partition, since of course stable_partition needs non const_iterators to do its work.

A possible solution is to replace auto with the proper type, which in this case was std::vector< std::string >::const_iterator. This forces the conversion from iterator to const_iterator on the second assignment.

Though, I don't like it. Types can easily and rapidly become unmanageable, so I'm looking for a solution that lets me use auto, without the need to declare something weird outside the loop. Any suggestion?


Solution

  • The most clear solution in my opinion is to pull std::stable_partition before the for. This will result in an equivalent algorithm.

    The problem is that stable_partition returns a iterator that can modify elements. Fortunately there is an implicit conversion from container::iterator to container::const_iterator (for most standard containers). To make the conversion you can specify the type of IterEnd with std::vector<T::const_iterator, or decltyp(Target.cbegin() or my personal preference:

    auto Iter = Target.cbegin();
    decltype(Iter) IterEnd = std::stable_partition(Target.begin(), Target.end(), Check);
    
    for (; Iter != IterEnd; ++Iter)
    {
    }
    

    For completeness you could keep all inside the for if you wish but it's less readable in my opinion:

    for (auto Iter = Target.cbegin(),
            IterEnd = (decltype(Iter)) std::stable_partition(Target.begin(), Target.end(), Check);
         Iter != IterEnd;
         ++Iter)
    {}