Is there a prettier / less-verbose way to use iterators in C++? From the tutorials I've seen, I either set up typedefs everywhere (which gets tedious to do for a lot of one-off for-loops):
typedef std::vector<std:pair<int, int> >::iterator BlahIterator;
or have verbose-looking for loops like:
for (std::vector<std:pair<int, int> >::iterator it = ... ) ...
Is there a better way?
In C++11 you can use the range-based for loop combined with the auto keyword:
for (auto& it : v) ...
With boost, you can use the FOR_EACH macro.
typedef pair<int, int> tElem;
BOOST_FOREACH( tElem e, aVector )
{
cout << e.first << " " << e.second << '\n';
}
The algorithms sort of get around that particular problem.
Especially with the new lambda functions.
std::for_each(c.begin(), c.end(), Action()); /* Where Action is your functor */
Or with lambda:
std::for_each(c.begin(), c.end(), [](type const& e) { /* Stuff */ });
Note: don't fall into the trap of using std::for_each to replace all loops. There are a whole bunch of algorithms that use iterators that allow you to manipulate or do operations based on the contents of a container.
With c++0x you can use the auto keyword:
for (auto i = v.begin(); i != v.end(); ++i) {}
I usually use the following naming pattern:
typedef std::pair<int, int> Blah;
typedef std::vector<Blah> Blahs;
and then use Blahs::iterator, i.e I don't name the iterator but the container (and usually the thing contained in it).
typedef is a very useful abstraction mechanism.
Note that a vector of "Blah" is called "Blahs" (i.e. just the plural), not a "BlahVector", because the specific container doesn't matter.
One possibility is to write your loop (or whatever code that uses the iterator) into a small generic algorithm of its own. By making it a template, the compiler can/will deduce the iterator type automatically:
template <class T>
do_something(T begin, T end) {
for (T pos = begin; pos != end; ++pos)
do_something_with(*pos);
}
I usually define this, though I've been told I'm going to hell for it:
#define forsn(i, s, n) for(int i = (s); i < (n); ++i)
#define forn(i, n) forsn(i, 0, n)
#define forall(it, g) for(typeof g.begin() it = g.begin(); it != g.end(); ++it)
Then, to loop from 0 to n, a common task, I say forn(i, n) foo(i);, and to loop any standard container c, I say forall(it, c) foo(it); Do note that typeof is a GCC extension to the standard.
Related
It seems natural to have an std::iterator for std::tuple. However it is not implemented, so programmers implement there own versions. One is for example found at Jonathan Müller's Blog.
Do I overlook something? Is there any reason why there is no "official version" for an tuple_iterator?
std::tuple is not a container, at least not in the sense of the standard library containers. It cannot be iterated with the usual methods because it holds objects of different types. Standard containers are homogenous containers, while std::tuple is a heterogeneous container.
This doesn't mean that you can't iterate over a tuple, but it's very cumbersome and you can't use the established syntax:
Let's imagine you want to iterate over a tuple the same way you iterate over a container like std::vector:
std::tuple<int, std::string, bool> t = {...};
for (auto it = t.begin(); it != t.end(); ++it)
{
auto elem = *it; // this cannot work the same way as with containers
// because each element is of a different type
}
There are a couple of things you could do. Use an iterator who holds a std::variant with the types of the container. Accessing the true object underneath is not as easy. And also this kind of iterator wouldn't be usable anywhere else in the standard library where an iterator is expected, at least not without some extra work.
Also there is work on a proposal for metaprogramming (reflexion, introspection) that has (or had, hadn't followed it) the following syntax:
std::tuple<int, std::string, bool> t = {...};
// something like this (can't remember the syntax exactly):
for constexpr ... (auto elem : t)
{
// only the common set of operations permitted with `elem`
// e.g. this is valid
std::cout << elem << std::endl;
// this is invalid:
//elem.size();
}
This would actually be unrolled at compile time resulting in the following code:
std::tuple<int, std::string, bool> t = {...};
{
int elem = std::get<0>(t);
std::cout << elem << std::endl;
}
{
std::string elem = std::get<1>(t);
std::cout << elem << std::endl;
}
{
bool elem = std::get<2>(t);
std::cout << elem << std::endl;
}
What is the C++ idiomatic way of creating a std::vector from the last n elements of a std::map?
I am not interested in preserving the order in the vector.
I can copy the elements, like this:
std::map< double, MyType > m;
size_t n = 3;
std::vector< MyType > v;
std::map< double, MyType >::iterator it = m.end();
while ( n-- ) { // assuming m.size() >= n
it--;
v.push_back(it->second);
}
But, is there any other way, more idiomatic, to do it?
std::copy would be suitable if you wanted to copy the types unchanged. However, std::map<T,U>::iterator_type::value_type is not U (the type you want to copy), but std::pair<T,U> (in other words, dereferencing a map iterator yields a pair of the key and value types), so a raw copy won't work.
So we need to copy the elements, performing a transformation along the way. That's what std::transform is for.
For convenience, I'm going to assume that your compiler supports C++11 lambda expressions and the auto keyword. If not, it can be fairly trivially rewritten as a functor. But we're looking for something roughly like this:
std::transform(map_first, map_last, std::back_inserter(vec), [](std::pair<double,MyType> p) { return p.second; });
Now we just need to fill in the two first parameters:
auto map_first = std::next(map.end(), -n);
auto map_last = map.end();
The only tricky part here is that map iterators are bidirectional, but not random-access, so we can't simply say map.end() - n. The - operator is not defined. Instead, we have to use std::next (which takes linear rather than constant time for bidirectional operators, but there's no way around that).
(Note, I haven't tried compiling this code, so it might require a small bit of tweaking)
std::transform would be the most idiomatic way. You need a functional
object:
template<typename PairType>
struct Second
{
typename PairType::second_type operator()( PairType const& obj ) const
{
return obj.second;
}
}
(If your doing much work with std::map or other things that use
std::pair, you'll have this in your toolbox.)
After that, it's a bit awkward because you only want the last n. Since
iterators into a map are not random access iterators, and you can't add
or subtract arbitrary values, the simplest solution is to copy them all,
then remove the ones you don't want:
std::vector<MyType>
extractLastN( std::map<double, MyType> const& source, size_t n )
{
std::vector<MyType> results;
std::transform( source.begin(), source.end(),
std::back_inserter( results ),
Second<std::map<double, MyType>::value_type>() );
if ( results.size() > n ) {
results.erase( results.begin(), results.end() - n );
}
return results;
}
This isn't the most efficient, but depending on n and where it is
used, it may be sufficient. If you do want to avoid the extra copying,
etc. (probably worthwhile only if n is typically much smaller than the
size of the map), you'll have to do something fancier:
std::vector<MyType>
extractLastN( std::map<double, MyType> const& source, ptrdiff_t n )
{
std::map<double, MyType>::const_iterator start
= source.size() <= n
? source.begin()
: std::prev( source.end(), n );
std::vector<MyType> results;
std::transform( start, source.end(),
std::back_inserter( results ),
Second<std::map<double, MyType>::value_type>() );
return results;
}
(If you don't have access to C++11, std::prev is simply:
template<typename IteratorType>
IteratorType
prev( IteratorType start, ptrdiff_t n )
{
std::advance( start, -n );
return start;
}
Again, if you're doing much with the standard library, you probably
already have it in your toolkit.)
Here's a simple Boost.Range version:
#include <boost/range/iterator_range_core.hpp>
#include <boost/range/adaptor/map.hpp>
//#include <boost/range/adaptor/reversed.hpp> // comment in for 'reversed'
#include <map>
#include <vector>
struct X{};
int main(){
std::map<int, X> m;
unsigned n = 0;
auto vec(boost::copy_range<std::vector<X>>(
boost::make_iterator_range(m, m.size()-n, 0)
| boost::adaptors::map_values
//| boost::adaptors::reversed // comment in to copy in reverse order
));
}
One way of doing it is using a simple for_each:
map<int,double> m;
vector<double> v;
//Fill map
auto siter = m.end();
advance(siter, -3);
for_each(siter, m.end(), [&](pair<int,double> p) { v.push_back(p.second); });
EDIT Even simpler way is using std::prev with for_each:
map<int,double> m;
vector<double> v;
//Fill map
for_each(prev(m.end(), 3), m.end(),
[&](pair<int,double> p) { v.push_back(p.second); });
Also, if you want fill the vector in reverse order you can use:
for_each(m.rbegin(), next(m.rbegin(), 3),
[&](pair<int,double> p) { v.push_back(p.second); });
First, what do we want to write to be idiomatic? I suggest:
std::vector<Mytype> v;
v.reserve(n);
std::transform(
limited(n, m.rbegin()),
limited_end(m.rend()),
std::back_inserter(v),
values_from(m)
);
Now we just have to make that code valid.
We can replace values_from(m) with a lambda (which doesn't need m), or implement it using James Kanze's class Second (in which case m is there for type deduction):
template <typename Map>
Second<Map::value_type> values_from(const Map &) {
return Second<Map::value_type>();
}
Implementing limited is a bit of a pain. It's a template function that returns an iterator. The iterator type it returns is a template that wraps another iterator type, and forwards everything on to it except that it keeps track of n, and acts like an end iterator when it has been advanced n times. limited_end returns an end iterator of the same type, so it compares equal either if the underlying iterators are equal, or if one of the iterators was created with limited_end and the other one has run n down to zero.
I don't have the code for this handy, but it's basically how you get _n equivalents of all the standard algorithms, not just copy_n. In this case, we want transform_n, but there isn't one.
An alternative to transform would be to use copy_n with a boost::transform_iterator wrapped around m.rbegin(). I won't do that here either, because I always have to check the docs to use transform_iterator.
Do it backwards:
assert(n <= m.size());
std::copy(m.rbegin(), m.rbegin()+n, std::back_inserter(v));
bidirectional iterators FTW.
OK, I obviously wasn't awake yet, and that was wishful thinking. I still prefer walking backwards to get the last n though, so a working version looks like this:
#include <map>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
// I'm assuming it's ok to copy min(m.size(), n)
template <typename Iter>
Iter safe_advance(Iter begin, Iter const &end, int distance)
{
while(distance-- > 0 && begin != end)
++begin;
return begin;
}
void copy_last_n(map<double,int> const &m,
vector<int> &v, int n)
{
transform(m.rbegin(), safe_advance(m.rbegin(), m.rend(), n),
back_inserter(v),
[](map<double,int>::value_type const &val)
{
return val.second;
}
);
}
James Kanze already wrote the Second functor - use that if you don't have access to lambdas.
in c++ 11 if we have a set<int> S; we could say:
for (auto i: S)
cout << i << endl;
but can we force i to be a iterator, I mean write a code that is equivalent to:
for (auto i = S.begin(); i != S.end(); i++)
cout << (i != s.begin()) ? " " : "" << *i;
or could we do something that we can understand the index of i in the set(or vector)?
and another question is how could we say that don't do this for all elements in S but for first half of them or all of them except the first one.
or when we have a vector<int> V, and want to print its first n values what should we do? I know we can create a new vector but it takes time to copy a vector to a new vector.
No, unluckily. See what the standard says:
The range-based for statement
for ( for-range-declaration : expression ) statement
is equivalent to
{
auto && __range = ( expression );
for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) {
for-range-declaration = *__begin;
statement
}
}
where __range, __begin, and __end are variables defined for exposition only
In other words, it already iterates from begin to end and already dereferences the iterator, which you never get to see.
The principle of the range-based for is to iterate over the whole range.
However you decide what the range is, therefore you can operate on the range itself.
template <typename It>
class RangeView {
public:
typedef It iterator;
RangeView(): _begin(), _end() {}
RangeView(iterator begin, iterator end): _begin(begin), _end(end) {}
iterator begin() const { return _begin; }
iterator end() const { return _end; }
private:
iterator _begin;
iterator _end;
};
template <typename C>
RangeView<typename C::iterator> rangeView(C& c, size_t begin, size_t end) {
return RangeView<typename C::iterator>(
std::next(c.begin(), begin),
std::next(c.begin(), end)
);
}
template <typename C>
RangeView<typename C::const_iterator> rangeView(C const& c, size_t begin, size_t end) {
return RangeView<typename C::const_iterator>(
std::next(c.begin(), begin),
std::next(c.begin(), end)
);
}
Okay, this seriously ressemble Boost.Range...
And now, let's use it!
for (auto i: rangeView(set, 1, 10)) {
// iterate through the second to the ninth element
}
No, you can't.
for (... : ...)
is called for instead of foreach only for the reason of not introducing a new keyword. The whole point of foreach is a quick short syntax for iterating all elements without caring for their index. For all other situations there's simple for which serves its purpose quite effectively.
For the general case, you'd have to use a seperate variable:
int i = 0;
for (auto x : s)
cout << (i++ ? " " : "") << x << endl;
There are, of course, tricks for certain containers like vector, but none work for every container.
You would probably be better off using the plain for loop for this purpose.
You can't in a set. Use the traditional for syntax or maintain your own index counter.
You can in a vector or other container with a flat layout like std::array or a C-style array. Change it to use a reference.:
for (auto &i: S)
Then you can compare the address of i with the address of s[0] to get the index.
Range-based for is intended for simple cases. I'd expect to to mildly useful while protoyping something but would expect uses of it mostly gone long before things actually become a product. It may possibly useful to make life for beginners easier, but this is an area I can't judge (but what seems to drive a lot of the recent C++ discussions).
The only somewhat constructive approach could be to use an adapter which references the underlying range and whose begin() and end() methods adjust the iterator appropriately. Also note that you probably want to hoist any special handling of the first or last element out of the loop processing the bulk of the data. Sure, it is only another check followed by a correctly predicted branch vs. no check and less pollution of the branch prediction tables.
The C++ std algorithms define a number of algorithms that take an input and an output sequence, and create the elements of the output sequence from the elements of the input sequence. (Best example being std::transform.)
The std algorithms obviously take iterators, so there's no question that the container for the OutputIterator has to exist prior to the algorithm being invoked.
That is:
std::vector<int> v1; // e.g. v1 := {1, 2, 3, 4, 5};
std::vector<int> squared;
squared.reserve(v1.size()); // not strictly necessary
std::transform(v1.begin(), v1.end(), std::back_inserter(squared),
[](int x) { return x*x; } ); // λ for convenience, needn't be C++11
And this is fine as far as the std library goes. When I find iterators too cumbersome, I often look to Boost.Range to simplify things.
In this case however, it seems that the mutating algorithms in Boost.Range also use OutputIterators.
So I'm currently wondering whether there's any convenient library out there, that allows me to write:
std::vector<int> const squared = convenient::transform(v1, [](int x) { return x*x; });
-- and if there is none, whether there is a reason that there is none?
Edit: example implementation (not sure if this would work in all cases, and whether this is the most ideal one):
template<typename C, typename F>
C transform(C const& input, F fun) {
C result;
std::transform(input.begin(), input.end(), std::back_inserter(result), fun);
return result;
}
(Note: I think convenient::transform will have the same performance characteristics than the handwritten one, as the returned vector won't be copied due to (N)RVO. Anyway, I think performance is secondary for this question.)
Edit/Note: Of the answers(comments, really) given so far, David gives a very nice basic generic example.
And Luc mentions a possible problem with std::back_inserter wrt. genericity.
Both just go to show why I'm hesitating to whip this up myself and why a "proper" (properly tested) library would be preferable to coding this myself.
My question phrased in bold above, namely is there one, or is there a reason there is none remains largely unanswered.
This is not meant as an answer to the question itself, it's a complement to the other answers -- but it wouldn't fit in the comments.
well - what if you wanted list or deque or some other sequence type container - it's pretty limiting.
namespace detail {
template<typename Iter, typename Functor>
struct transform {
Iter first, last;
Functor functor;
template<typename Container> // SFINAE is also available here
operator Container()
{
Container c;
std::transform(first, last, std::back_inserter(c), std::forward<Functor>(functor));
return c;
}
};
} // detail
template<typename Iter, typename Functor>
detail::transform<Iter, typename std::decay<Functor>::type>
transform(Iter first, Iter last, Functor&& functor)
{ return { first, last, std::forward<Functor>(functor) }; }
While this would work with a handful of containers, it's still not terribly generic since it requires that the container be 'compatible' with std::back_inserter(c) (BackInsertable?). Possibly you could use SFINAE to instead use std::inserter with c.begin() if c.push_back() is not available (left as an exercise to the reader).
All of this also assume that the container is DefaultConstructible -- consider containers that make use of scoped allocators. Presumably that loss of genericity is a feature, as we're only trying to cover the 'simplest' uses.
And this is in fact while I would not use such a library: I don't mind creating the container just outside next to the algorithm to separate the concerns. (I suppose this can be considered my answer to the question.)
IMHO, the point of such an algorithm is to be generic, i.e. mostly container agnostic. What you are proposing is that the transform function be very specific, and return a std::vector, well - what if you wanted list or deque or some other sequence type container - it's pretty limiting.
Why not wrap if you find it so annoying? Create your own little utilities header which does this - after all, it's pretty trivial...
The Boost.Range.Adaptors can be kind of seen as container-returning algorithms. Why not use them?
The only thing that needs to be done is to define a new range adaptor create<T> that can be piped into the adapted ranges and produces the desired result container:
template<class T> struct converted{}; // dummy tag class
template<class FwdRange, class T>
T operator|(FwdRange const& r, converted<T>){
return T(r.begin(), r.end());
}
Yep, that's it. No need for anything else. Just pipe that at the end of your adaptor list.
Here could be a live example on Ideone. Alas, it isn't, because Ideone doesn't provide Boost in C++0x mode.. meh. In any case, here's main and the output:
int main(){
using namespace boost::adaptors;
auto range = boost::irange(1, 10);
std::vector<int> v1(range.begin(), range.end());
auto squared = v1 | transformed([](int i){ return i * i; });
boost::for_each(squared, [](int i){ std::cout << i << " "; });
std::cout << "\n========================\n";
auto modded = squared | reversed
| filtered([](int i){ return (i % 2) == 0; })
| converted<std::vector<int>>(); // gimme back my vec!
modded.push_back(1);
boost::for_each(modded, [](int i){ std::cout << i << " "; });
}
Output:
1 4 9 16 25 36 49 64 81
========================
64 36 16 4 1
There is no one and correct way of enabling
std::vector<int> const squared =
convenient::transform(v1, [](int x) { return x*x; });
without a potential performance cost. You either need an explicit
std::vector<int> const squared =
convenient::transform<std::vector> (v1, [](int x) { return x*x; });
Note the explicit mentioning of the container type: Iterators don't tell anything about the container they belong to. This becomes obvious if you remind that a container's iterator is allowed by the standard to be an ordinary pointer.
Letting the algorithm take a container instead of iterators is not a solution, either. That way, the algorithm can't know how to correctly get the first and last element. For example, a long int-array does not have methods for begin(), end() and length(), not all containers have random access iterators, not operator[] defined. So there is no truly generic way to take containers.
Another possibility that allows for container-agnostic, container-returning algorithms would be some kind of generic factory (see live at http://ideone.com/7d4E2):
// (not production code; is even lacking allocator-types)
//-- Generic factory. -------------------------------------------
#include <list>
template <typename ElemT, typename CacheT=std::list<ElemT> >
struct ContCreator {
CacheT cache; // <-- Temporary storage.
// Conversion to target container type.
template <typename ContT>
operator ContT () const {
// can't even move ...
return ContT (cache.begin(), cache.end());
}
};
Not so much magic there apart from the templated cast operator. You then return that thing from your algorithm:
//-- A generic algorithm, like std::transform :) ----------------
ContCreator<int> some_ints () {
ContCreator<int> cc;
for (int i=0; i<16; ++i) {
cc.cache.push_back (i*4);
}
return cc;
}
And finally use it like this to write magic code:
//-- Example. ---------------------------------------------------
#include <vector>
#include <iostream>
int main () {
typedef std::vector<int>::iterator Iter;
std::vector<int> vec = some_ints();
for (Iter it=vec.begin(), end=vec.end(); it!=end; ++it) {
std::cout << *it << '\n';
}
}
As you see, in operator T there's a range copy.
A move might be possible by means of template specialization in case the target and source containers are of the same type.
Edit: As David points out, you can of course do the real work inside the conversion operator, which will come at probably no extra cost (with some more work it can be done more convenient; this is just for demonstration):
#include <list>
template <typename ElemT, typename Iterator>
struct Impl {
Impl(Iterator it, Iterator end) : it(it), end(end) {}
Iterator it, end;
// "Conversion" + Work.
template <typename ContT>
operator ContT () {
ContT ret;
for ( ; it != end; ++it) {
ret.push_back (*it * 4);
}
return ret;
}
};
template <typename Iterator>
Impl<int,Iterator> foo (Iterator begin, Iterator end) {
return Impl<int,Iterator>(begin, end);
}
#include <vector>
#include <iostream>
int main () {
typedef std::vector<int>::iterator Iter;
const int ints [] = {1,2,4,8};
std::vector<int> vec = foo (ints, ints + sizeof(ints) / sizeof(int));
for (Iter it=vec.begin(), end=vec.end(); it!=end; ++it) {
std::cout << *it << '\n';
}
}
The one requirement is that the target has a push_back method. Using std::distance to reserve a size may lead to sub-optimal performance if the target-container-iterator is not a random-access one.
Again, a no-answer, but rather a follow up from the comments to another answer
On the genericity of the returned type in the questions code
The code as it stands does not allow the conversion of the return type, but that can be easily solvable by providing two templates:
template <typename R, typename C, typename F>
R transform( C const & c, F f ) {_
R res;
std::transform( c.begin(), c.end(), std::back_inserter(res), f );
return res;
}
template <typename C, typename F>
C transform( C const & c, F f ) {
return transform<C,C,F>(c,f);
}
std::vector<int> src;
std::vector<int> v = transform( src, functor );
std::deque<int> d = transform<std::deque<int> >( src, functor );
My question is sure a simple one for anybody familiar with C++ syntax. I'm learning C++ and this is some sort of homework.
template<typename Iter>
void quickSort(Iter begin, Iter end)
{
//..
auto pivot = * ( begin + (end - begin)/2 );
//..
}
pivot is supposed to contain the value from the center of the interval [begin, end].
The code I wrote there works, but auto is a keyword from the new C++11 language standard. How to do it the old-way? What do I write instead of auto?
typename std::iterator_traits<Iter>::value_type
This will work if your template is instantiated with Iter as a pointer type.
By the way, typename isn't part of the type itself. It tells the compiler that value_type really is a type. If it were the name of a function or a static data member, then that affects the syntax. The compiler doesn't necessarily know what it is, since the specialization of iterator_traits for Iter might not be visible when the template is compiled.
This will also work starting c++ 11:
typename Iter::value_type
So you do not have to type the whole std::iterator_traits thing.
Starting from C++20 you can also use the following (together with an example):
#include <iostream>
#include <vector>
template<typename Iter>
void quickSort(Iter begin, Iter end)
{
using T = std::iter_value_t<Iter>;
//..
T pivot = * ( begin + (end - begin)/2 );
std::cout << "Element: " << pivot << std::endl;
//..
}
int main(int argc, char* argv[]){
std::vector<int> vec = {0,1,2,3,4,5};
quickSort<std::vector<int>::iterator>(vec.begin(), vec.end());
return 0;
}
output:
Element: 3
The answer of Steve is right; in C++98, you have to use std::iterator_traits or you can use Iter::value_type if you know that the iterator has this typedef (e.g. is derived from std::iterator).
However, there is another problem in your code: you normally can't simply divide iterators. This works with pointers, of course, but not in the more general case. A more general approach would be:
Iter itPivot = std::advance(begin, std::distance(begin, end)/2);