Initializing std::vector with iterative function calls
Sadly, there is no standard facility to do this.
For your specific example, you could use Boost.Iterator's counting_iterator
like this:
std::vector<int> v(boost::counting_iterator<int>(0),
boost::counting_iterator<int>(10));
Or even with Boost.Range like this:
auto v(boost::copy_range<std::vector<int>>(boost::irange(0,10)));
(copy_range
will basically just return std::vector<int>(begin(range), end(range))
and is a great way to adopt full range construction to exisiting containers that only support range construction with two iterators.)
Now, for the general purpose case with a generator function (like std::rand
), there is the function_input_iterator
. When incremented, it calls the generator and saves the result, which is then returned when dereferencing it.
#include <vector>
#include <iostream>
#include <cmath>
#include <boost/iterator/function_input_iterator.hpp>
int main(){
std::vector<int> v(boost::make_function_input_iterator(std::rand, 0),
boost::make_function_input_iterator(std::rand,10));
for(auto e : v)
std::cout << e << " ";
}
Live example.
Sadly, since function_input_iterator
doesn't use Boost.ResultOf, you need a function pointer or a function object type that has a nested result_type
. Lambdas, for whatever reason, don't have that. You could pass the lambda to a std::function
(or boost::function
) object, which defines that. Here's an example with std::function
. One can only hope that Boost.Iterator will make use of Boost.ResultOf someday, which will use decltype
if BOOST_RESULT_OF_USE_DECLTYPE
is defined.
The world is too large for C++ to ship a solution for everything. However, C++ doesn't want to be a huge supermarket full of ready meals for every conceivable palate. Rather, it is a small, well-equipped kitchen in which you, the C++ Master Chef, can cook up any solution you desire.
Here's a silly and very crude example of a sequence generator:
#include <iterator>
struct sequence_iterator : std::iterator<std::input_iterator_tag, int>
{
sequence_iterator() : singular(true) { }
sequence_iterator(int a, int b) : singular(false) start(a), end(b) { }
bool singular;
int start;
int end;
int operator*() { return start; }
void operator++() { ++start; }
bool operator==(sequence_iterator const & rhs) const
{
return (start == end) == rhs.singular;
}
bool operator!=(sequence_iterator const & rhs) const
{
return !operator==(rhs);
}
};
Now you can say:
std::vector<int> v(sequence_iterator(1,10), sequence_iterator());
In the same vein, you can write a more general gadget that "calls a given functor a given number of times", etc. (e.g. take a function object by templated copy, and use the counters as repetition counters; and dereferencing calls the functor).
If you're using a compiler that supports lambdas as you use in your question, then chances are pretty good it also includes std::iota
, which at least makes the counting case a little cleaner:
std::vector <int> vec(10);
std::iota(begin(vec), end(vec), 0);
For this scenario (and quite a few others, I think) we'd really prefer an iota_n
though:
namespace stdx {
template <class FwdIt, class T>
void iota_n(FwdIt b, size_t count, T val = T()) {
for ( ; count; --count, ++b, ++val)
*b = val;
}
}
Which, for your case you'd use like:
std::vector<int> vec;
stdx::iota_n(std::back_inserter(vec), 10);
As to why this wasn't included in the standard library, I really can't even guess. I suppose this could be seen as an argument in favor of ranges, so the algorithm would take a range, and we'd have an easy way to create a range from either a begin/end pair or a begin/count pair. I'm not sure I completely agree with that though -- ranges do seem to work well in some cases, but in others they make little or no sense. I'm not sure that without more work, we have an answer that's really a lot better than a pair of iterators.