Reputation: 1219
In my C++03 code, I have a lot of functions that look like this:
class A {
public:
template <Iterator>
void doSomethingWithObjects(Iterator begin, Iterator end) {
for (Iterator point = begin; point != end; point++) {
mInternal.doSomething(*point);
}
}
private:
DataStructure mInternal;
};
I'm trying to use C++11's features as much as possible in new code, in particular the range-based for loop. My question is, how would I do this with templated iterators? Is there a magic C++ structure that takes two templated iterator types, and turns them into a range expression? In other words, I'm looking for something like this:
class A {
public:
template <Iterator>
void doSomethingWithObjects(Iterator begin, Iterator end) {
static_assert(std::is_same<Point, typename std::decay<Iterator>::type>::value, "wrong type mate!"); // extra credit
for (auto&& point : std::magic(begin, end)) {
mInternal.doSomething(point);
}
}
private:
DataStructure mInternal;
};
If there is a new, preferred ways to do this kind of "add a number of objects to this structure" in C++11, I'm all ears, too.
Upvotes: 1
Views: 478
Reputation: 303870
You don't actually need to turn them into anything. Just use the iterators with std::for_each
:
template <Iterator>
void doSomethingWithObjects(Iterator begin, Iterator end) {
std::for_each(begin, end, [this](auto&& point){
mInternal.doSomething(point);
}
// C++11 version
std::for_each(begin, end, [this](decltype(*begin)& point) {
mInternal.doSomething(point);
}
}
or write the simple loop:
template <Iterator>
void doSomethingWithObjects(Iterator begin, Iterator end) {
for (; begin != end; ++begin) {
mInternal.doSomething(*begin);
}
}
Upvotes: 0
Reputation: 206717
I would add a function overload and keep the existing function around to make the transition gradual and less disruptive.
template <typename Container>
void doSomethingWithObjects(Container&& c) {
for (auto&& item: c) {
mInternal.doSomething(item);
}
}
Upvotes: 1
Reputation: 275896
template<class It>
struct range_t {
It b; It e;
It begin() const { return b; }
It end() const { return e; }
};
template<class It>
range_t<It> range( It b, It e ) {
return {std::forward<It>(b), std::forward<It>(e)};
}
then:
template <Iterator>
void doSomethingWithObjects(Iterator begin, Iterator end) {
for (auto&& point : range(begin, end)) {
mInternal.doSomething(point);
}
}
and bob is your uncle.
"Range-v3" is a library undergoing the standardization process that contains stuff like this already. Boost also has similar mechanisms.
But this kind of thing is simple enough to roll your own and forget about it. (Better versions include empty
, conditionally support size
and []
, can be constructed from containers and C arrays and anything iterable, know if they are condiguous, conditionally store a copy of the incoming container for reference lifetime extension, etc: but you don't really need any of that).
Upvotes: 2
Reputation: 137394
There's nothing in the standard library. Boost has make_iterator_range
, a simplified version of which is trivial to write:
template<class Iterator>
struct iter_range {
Iterator begin_, end_;
Iterator begin() const { return begin_; }
Iterator end() const { return end_; }
};
template<class Iterator>
iter_range<Iterator> make_range(Iterator b, Iterator e) { return {b, e}; }
The original question just called push_back
. For that, it doesn't need a loop. Just use the C++03 range overload of insert
:
mInternal.insert(mInternal.end(), begin, end);
Upvotes: 5