casting a returned iterator to const

casting a returned iterator to const



I have the following for statement in my code:


for


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.


const_iterator


cbegin()


cbegin()


cend()


stable_partition


stable_partition


non const_iterators



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.


std::vector< std::string >::const_iterator


iterator


const_iterator



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?





I am not sure about your idea of type unmanageability. Being explicit in your type declaration, if that solves your problem, is a fine approach. auto is convenient, but I wouldn’t say it is necessarily more manageable than being clear on the types you are using.
– Brian
Aug 29 at 10:53


auto





I would definitely move all this stuff out of loop prologue. auto IterTarget.cbegin(); decltype(Target)::const_iterator const IterEndstd::stable_partition(Target.begin(), Target.end(), Check);
– VTT
Aug 29 at 10:56


auto IterTarget.cbegin(); decltype(Target)::const_iterator const IterEndstd::stable_partition(Target.begin(), Target.end(), Check);





you can use decltype(Target.cbegin()) IterEnd
– Nishant Singh
Aug 29 at 10:57



decltype(Target.cbegin()) IterEnd





Careful with your terminology: making the iterator const doesn't make sense as you'll be incrementing it. ;)
– Lightness Races in Orbit
Aug 29 at 11:01





Also note that stable_partition reorders the elements of Target (and possibly the first), so Iter might not point to the first element (depends on the container used). Invoke stable_partition first before you initialize Iter.
– dan
Aug 29 at 11:09



stable_partition


Target


Iter


stable_partition


Iter




2 Answers
2



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


std::stable_partition


for



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:


stable_partition


container::iterator


container::const_iterator


IterEnd


std::vector<T::const_iterator


decltyp(Target.cbegin()


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


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





The call to std::stable_partition is in the preamble, so while philosophically we may claim it's "during the loop", it's not really, and thus your solution is not only good but also equivalent to the request. +1 but consider de-wrongising that opening para
– Lightness Races in Orbit
Aug 29 at 11:02



std::stable_partition





@LightnessRacesinOrbit yes, I see your point. Edited.
– bolov
Aug 29 at 11:05





You still say that the OP "needs" to pull std::stable_partition before the for, which is not true, though it does look much better this way (and I'm not sure the OP can get exactly what they want without it due to the single declaration statement in the preamble mixed with for - perhaps that's what you meant acutally?)
– Lightness Races in Orbit
Aug 29 at 11:09


std::stable_partition


for


for





@LightnessRacesinOrbit hm... he could by using a cast
– bolov
Aug 29 at 11:10





Indeed but I believe the point of the question is "cast to what? (without writing everything out rigidly)" - your answer does solve that perfectly by splitting the declaration into two, allowing us to use auto/decltype at both stages.
– Lightness Races in Orbit
Aug 29 at 11:12




Here's one way to express the idea through a functional interface:


#include <vector>
#include <algorithm>
#include <iostream>

namespace detail
template<class Container, class F>
struct const_partitioned_target

using container_type = std::decay_t<Container>;
using const_iterator = typename container_type::const_iterator;

const_partitioned_target(Container& cont, F f)
: first(cont.cbegin())
, last(std::partition(cont.begin(), cont.end(), f))




const_iterator begin() const return first;

const_iterator end() const return last;

const_iterator first, last;
;


template<class Container, class F>
auto const_partitioned_target(Container& cont, F&& f)

return detail::const_partitioned_target<Container, std::decay_t<F>>(cont, std::forward<F>(f));
;

int main()

std::vector<int> Target 1, 2, 6, 9, 10, 20, 30, 40 ;

auto Check = (auto&& x)

return x < 10;
;

for(auto&& elem : const_partitioned_target(Target, Check))

// elem will have the type: int const&
std::cout << elem << 'n';




expected output:


1
2
6
9






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)