Related
Say i have the following scenario:
namespace detail
{
using duk_c_function_t = std::function<duk_ret_t(duk_context*)>;
template<typename T_Return(typename ... T_Params), std::function<T_Return(T_Params)>
duk_ret_t duk_function_proxy(duk_context* ctx)
{
const int n = sizeof...(T_Params); //real number of arguments passed.
duk_idx_t num_arguments = duk_get_top(ctx); //Number of arguments from javascript
int x = duk_require_int(ctx, 0); //Get integer -> parameter no 1
const char* c = duk_require_string(ctx, 1); //Get string -> parameter no 2
}
}
template<typename T_Return(typename ... T_Params)>
duk_c_function_t duk_function(std::function<T_Return(T_Params ...) function_item)
{
return duk_c_function_t(detail::duk_function_proxy<function_item>);
}
Where duk_function returns a function of the signature duk_ret_t function(duk_context* ctx) { ... }. Now, i know how to call the function object in duk_function_proxy with the variadic templates and such. But there is one problem for me: The javascript interpreter i am using requires that, for every c-function i want to expose, i need query the parameters from the stack, as shown in duk_function_proxy. However, with that being the case, i dont know how to call the function object - i can only store the queried parameters in some sort of container, and thus i cannot call the function object with the given signature. Is there any way to store my queried parameters in some sort of container, and then unpack and pass it to the function object as parameters? I query the required parameters based on the variadic template list, as seen in the prototype.
In short:
I want to iterate over T_Params, get and store the corresponding variables using duk_require_* (in some sort of container), and then use those values to call the function object, which is passed as a template argument.
this should get you started. I've simulated the DUK interface since it's not installed on my machine but you'll get the idea:
#include <iostream>
#include <string>
#include <functional>
#include <utility>
struct duk_context;
const char* duk_require_string(duk_context*, int i)
{
static constexpr const char * strings[] = {
"i like",
"hairy",
"ducks"
};
return strings[i];
}
int duk_require_int(duk_context*, int i)
{
return i * 6;
}
template<class Type> auto get_arg(duk_context* ctx, int i) -> Type;
template<> auto get_arg<std::string>(duk_context* ctx, int i) -> std::string
{
return duk_require_string(ctx, i);
}
template<> auto get_arg<int>(duk_context* ctx, int i) -> int
{
return duk_require_int(ctx, i);
}
template<class...Args, size_t...Is>
void get_args_impl(duk_context* context, const std::function<void(Args...)>& f, std::index_sequence<Is...>)
{
using tuple_type = std::tuple<Args...>;
f(get_arg<std::tuple_element_t<Is, tuple_type>>(context, Is)...);
}
template<class...Args>
void get_args(duk_context* context, const std::function<void(Args...)>& f)
{
get_args_impl<Args...>(context, f, std::index_sequence_for<Args...>());
}
void foo(std::string a, int b, std::string c)
{
std::cout << a << " " << b << " " << c << std::endl;
}
int main()
{
duk_context* ctx = nullptr;
get_args(ctx, std::function<void(std::string, int, std::string)>(&foo));
return 0;
}
expected output:
i like 6 ducks
C++11 provides multiple ways to iterate over containers. For example:
Range-based loop
for(auto c : container) fun(c)
std::for_each
for_each(container.begin(),container.end(),fun)
However what is the recommended way to iterate over two (or more) containers of the same size to accomplish something like:
for(unsigned i = 0; i < containerA.size(); ++i) {
containerA[i] = containerB[i];
}
Rather late to the party. But: I would iterate over indices. But not with the classical for loop but instead with a range-based for loop over the indices:
for(unsigned i : indices(containerA)) {
containerA[i] = containerB[i];
}
indices is a simple wrapper function which returns a (lazily evaluated) range for the indices. Since the implementation – though simple – is a bit too long to post it here, you can find an implementation on GitHub.
This code is as efficient as using a manual, classical for loop.
If this pattern occurs often in your data, consider using another pattern which zips two sequences and produces a range of tuples, corresponding to the paired elements:
for (auto& [a, b] : zip(containerA, containerB)) {
a = b;
}
The implementation of zip is left as an exercise for the reader, but it follows easily from the implementation of indices.
(Before C++17 you’d have to write the following instead:)
for (auto&& items : zip(containerA, containerB))
get<0>(items) = get<1>(items);
i wonder why no one mentioned this:
auto itA = vectorA.begin();
auto itB = vectorB.begin();
while(itA != vectorA.end() || itB != vectorB.end())
{
if(itA != vectorA.end())
{
++itA;
}
if(itB != vectorB.end())
{
++itB;
}
}
PS: if the container sizes don't match, then you may need to put each container specific code into its corresponding if block.
For your specific example, just use
std::copy_n(contB.begin(), contA.size(), contA.begin())
For the more general case, you can use Boost.Iterator's zip_iterator, with a small function to make it usable in range-based for loops. For most cases, this will work:
template<class... Conts>
auto zip_range(Conts&... conts)
-> decltype(boost::make_iterator_range(
boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))))
{
return {boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))};
}
// ...
for(auto&& t : zip_range(contA, contB))
std::cout << t.get<0>() << " : " << t.get<1>() << "\n";
Live example.
However, for full-blown genericity, you probably want something more like this, which will work correctly for arrays and user-defined types that don't have member begin()/end() but do have begin/end functions in their namespace. Also, this will allow the user to specifically get const access through the zip_c... functions.
And if you're an advocate of nice error messages, like me, then you probably want this, which checks if any temporary containers were passed to any of the zip_... functions, and prints a nice error message if so.
There are a lot of ways to do specific things with multiple containers as provided in the algorithm header. For instance, in the example you've given, you could use std::copy instead of an explicit for loop.
On the other hand, there isn't any built-in way to generically iterate multiple containers other than a normal for loop. This isn't surprising because there are a lot of ways to iterate. Think about it: you could iterate through one container with one step, one container with another step; or through one container until it gets to the end then start inserting while you go through to the end of the other container; or one step of the first container for every time you completely go through the other container then start over; or some other pattern; or more than two containers at a time; etc ...
However, if you wanted to make your own "for_each" style function that iterates through two containers only up to the length of the shortest one, you could do something like this:
template <typename Container1, typename Container2>
void custom_for_each(
Container1 &c1,
Container2 &c2,
std::function<void(Container1::iterator &it1, Container2::iterator &it2)> f)
{
Container1::iterator begin1 = c1.begin();
Container2::iterator begin2 = c2.begin();
Container1::iterator end1 = c1.end();
Container2::iterator end2 = c2.end();
Container1::iterator i1;
Container2::iterator i2;
for (i1 = begin1, i2 = begin2; (i1 != end1) && (i2 != end2); ++it1, ++i2) {
f(i1, i2);
}
}
Obviously you can make any kind of iterations strategy you want in a similar way.
Of course, you might argue that just doing the inner for loop directly is easier than writing a custom function like this ... and you'd be right, if you are only going to do it one or two times. But the nice thing is that this is very reusable. =)
In case when you need to iterate simultaneously over 2 containers only, there is an extended version of standard for_each algorithm in boost range library, e.g:
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/bind.hpp>
#include <boost/range/algorithm_ext/for_each.hpp>
void foo(int a, int& b)
{
b = a + 1;
}
int main()
{
std::vector<int> contA = boost::assign::list_of(4)(3)(5)(2);
std::vector<int> contB(contA.size(), 0);
boost::for_each(contA, contB, boost::bind(&foo, _1, _2));
// contB will be now 5,4,6,3
//...
return 0;
}
When you need to handle more than 2 containers in one algorithm, then you need to play with zip.
another solution could be capturing a reference of the iterator of the other container in a lambda and using post increment operator on that. for example simple copy would be:
vector<double> a{1, 2, 3};
vector<double> b(3);
auto ita = a.begin();
for_each(b.begin(), b.end(), [&ita](auto &itb) { itb = *ita++; })
inside lambda you can do whatever with ita and then increment it. This easily extends to the multiple containers case.
A range-library provides this and other very helpful functionality. The following example uses Boost.Range. Eric Niebler's rangev3 should be a good alternative.
#include <boost/range/combine.hpp>
#include <iostream>
#include <vector>
#include <list>
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& i: boost::combine(v, l))
{
int ti;
char tc;
boost::tie(ti,tc) = i;
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
C++17 will make this even better with structured bindings:
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& [ti, tc]: boost::combine(v, l))
{
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
I'm a bit late too; but you can use this (C-style variadic function):
template<typename T>
void foreach(std::function<void(T)> callback, int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
std::vector<T> v = va_arg(args, std::vector<T>);
std::for_each(v.begin(), v.end(), callback);
}
va_end(args);
}
foreach<int>([](const int &i) {
// do something here
}, 6, vecA, vecB, vecC, vecD, vecE, vecF);
or this (using a function parameter pack):
template<typename Func, typename T>
void foreach(Func callback, std::vector<T> &v) {
std::for_each(v.begin(), v.end(), callback);
}
template<typename Func, typename T, typename... Args>
void foreach(Func callback, std::vector<T> &v, Args... args) {
std::for_each(v.begin(), v.end(), callback);
return foreach(callback, args...);
}
foreach([](const int &i){
// do something here
}, vecA, vecB, vecC, vecD, vecE, vecF);
or this (using a brace-enclosed initializer list):
template<typename Func, typename T>
void foreach(Func callback, std::initializer_list<std::vector<T>> list) {
for (auto &vec : list) {
std::for_each(vec.begin(), vec.end(), callback);
}
}
foreach([](const int &i){
// do something here
}, {vecA, vecB, vecC, vecD, vecE, vecF});
or you can join vectors like here: What is the best way to concatenate two vectors? and then iterate over big vector.
I personally prefer using what is already in the STL (in the <algorithm> header) if possible. std::transform has a signature that can take two input iterators. So at least for the case of two input containers you could do:
std::transform(containerA.begin(), containerA.end(), containerB.begin(), outputContainer.begin(), [&](const auto& first, const auto& second){
return do_operation(first, second);
});
Note that the outputContainer can also be one of the input containers. But one limitation is that you cannot do a post update operation if you are modifying one of the containers in place.
The answer is here!... when C++23 comes.
#include <algorithm>
#include <forward_list>
#include <ranges>
#include <array>
#include <iostream>
int main()
{
auto foos = std::to_array({ 1, 2, 3, 4, 5 });
auto woos = std::to_array({ 6, 7, 8, 9, 10 });
auto fooswoos = std::views::zip(foos,woos);
for(auto [foo, woo] : fooswoos) {
woo += foo;
}
std::ranges::for_each(woos, [](const auto& e) { std::cout << e << '\n'; });
return 0;
}
So, what's happening?
We are constructing a special "view". This view allows us to look at containers as if they were other structures without actually doing any copying or anything like that. Using a structured binding we are able to take a reference to each aligning element per iteration and do whatever we want to it (and safely)
Check it out on compiler explorer right now!
Here is one variant
template<class ... Iterator>
void increment_dummy(Iterator ... i)
{}
template<class Function,class ... Iterator>
void for_each_combined(size_t N,Function&& fun,Iterator... iter)
{
while(N!=0)
{
fun(*iter...);
increment_dummy(++iter...);
--N;
}
}
Example usage
void arrays_mix(size_t N,const float* x,const float* y,float* z)
{
for_each_combined(N,[](float x,float y,float& z){z=x+y;},x,y,z);
}
C++11 provides multiple ways to iterate over containers. For example:
Range-based loop
for(auto c : container) fun(c)
std::for_each
for_each(container.begin(),container.end(),fun)
However what is the recommended way to iterate over two (or more) containers of the same size to accomplish something like:
for(unsigned i = 0; i < containerA.size(); ++i) {
containerA[i] = containerB[i];
}
Rather late to the party. But: I would iterate over indices. But not with the classical for loop but instead with a range-based for loop over the indices:
for(unsigned i : indices(containerA)) {
containerA[i] = containerB[i];
}
indices is a simple wrapper function which returns a (lazily evaluated) range for the indices. Since the implementation – though simple – is a bit too long to post it here, you can find an implementation on GitHub.
This code is as efficient as using a manual, classical for loop.
If this pattern occurs often in your data, consider using another pattern which zips two sequences and produces a range of tuples, corresponding to the paired elements:
for (auto& [a, b] : zip(containerA, containerB)) {
a = b;
}
The implementation of zip is left as an exercise for the reader, but it follows easily from the implementation of indices.
(Before C++17 you’d have to write the following instead:)
for (auto&& items : zip(containerA, containerB))
get<0>(items) = get<1>(items);
i wonder why no one mentioned this:
auto itA = vectorA.begin();
auto itB = vectorB.begin();
while(itA != vectorA.end() || itB != vectorB.end())
{
if(itA != vectorA.end())
{
++itA;
}
if(itB != vectorB.end())
{
++itB;
}
}
PS: if the container sizes don't match, then you may need to put each container specific code into its corresponding if block.
For your specific example, just use
std::copy_n(contB.begin(), contA.size(), contA.begin())
For the more general case, you can use Boost.Iterator's zip_iterator, with a small function to make it usable in range-based for loops. For most cases, this will work:
template<class... Conts>
auto zip_range(Conts&... conts)
-> decltype(boost::make_iterator_range(
boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))))
{
return {boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))};
}
// ...
for(auto&& t : zip_range(contA, contB))
std::cout << t.get<0>() << " : " << t.get<1>() << "\n";
Live example.
However, for full-blown genericity, you probably want something more like this, which will work correctly for arrays and user-defined types that don't have member begin()/end() but do have begin/end functions in their namespace. Also, this will allow the user to specifically get const access through the zip_c... functions.
And if you're an advocate of nice error messages, like me, then you probably want this, which checks if any temporary containers were passed to any of the zip_... functions, and prints a nice error message if so.
There are a lot of ways to do specific things with multiple containers as provided in the algorithm header. For instance, in the example you've given, you could use std::copy instead of an explicit for loop.
On the other hand, there isn't any built-in way to generically iterate multiple containers other than a normal for loop. This isn't surprising because there are a lot of ways to iterate. Think about it: you could iterate through one container with one step, one container with another step; or through one container until it gets to the end then start inserting while you go through to the end of the other container; or one step of the first container for every time you completely go through the other container then start over; or some other pattern; or more than two containers at a time; etc ...
However, if you wanted to make your own "for_each" style function that iterates through two containers only up to the length of the shortest one, you could do something like this:
template <typename Container1, typename Container2>
void custom_for_each(
Container1 &c1,
Container2 &c2,
std::function<void(Container1::iterator &it1, Container2::iterator &it2)> f)
{
Container1::iterator begin1 = c1.begin();
Container2::iterator begin2 = c2.begin();
Container1::iterator end1 = c1.end();
Container2::iterator end2 = c2.end();
Container1::iterator i1;
Container2::iterator i2;
for (i1 = begin1, i2 = begin2; (i1 != end1) && (i2 != end2); ++it1, ++i2) {
f(i1, i2);
}
}
Obviously you can make any kind of iterations strategy you want in a similar way.
Of course, you might argue that just doing the inner for loop directly is easier than writing a custom function like this ... and you'd be right, if you are only going to do it one or two times. But the nice thing is that this is very reusable. =)
In case when you need to iterate simultaneously over 2 containers only, there is an extended version of standard for_each algorithm in boost range library, e.g:
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/bind.hpp>
#include <boost/range/algorithm_ext/for_each.hpp>
void foo(int a, int& b)
{
b = a + 1;
}
int main()
{
std::vector<int> contA = boost::assign::list_of(4)(3)(5)(2);
std::vector<int> contB(contA.size(), 0);
boost::for_each(contA, contB, boost::bind(&foo, _1, _2));
// contB will be now 5,4,6,3
//...
return 0;
}
When you need to handle more than 2 containers in one algorithm, then you need to play with zip.
another solution could be capturing a reference of the iterator of the other container in a lambda and using post increment operator on that. for example simple copy would be:
vector<double> a{1, 2, 3};
vector<double> b(3);
auto ita = a.begin();
for_each(b.begin(), b.end(), [&ita](auto &itb) { itb = *ita++; })
inside lambda you can do whatever with ita and then increment it. This easily extends to the multiple containers case.
A range-library provides this and other very helpful functionality. The following example uses Boost.Range. Eric Niebler's rangev3 should be a good alternative.
#include <boost/range/combine.hpp>
#include <iostream>
#include <vector>
#include <list>
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& i: boost::combine(v, l))
{
int ti;
char tc;
boost::tie(ti,tc) = i;
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
C++17 will make this even better with structured bindings:
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& [ti, tc]: boost::combine(v, l))
{
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
I'm a bit late too; but you can use this (C-style variadic function):
template<typename T>
void foreach(std::function<void(T)> callback, int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
std::vector<T> v = va_arg(args, std::vector<T>);
std::for_each(v.begin(), v.end(), callback);
}
va_end(args);
}
foreach<int>([](const int &i) {
// do something here
}, 6, vecA, vecB, vecC, vecD, vecE, vecF);
or this (using a function parameter pack):
template<typename Func, typename T>
void foreach(Func callback, std::vector<T> &v) {
std::for_each(v.begin(), v.end(), callback);
}
template<typename Func, typename T, typename... Args>
void foreach(Func callback, std::vector<T> &v, Args... args) {
std::for_each(v.begin(), v.end(), callback);
return foreach(callback, args...);
}
foreach([](const int &i){
// do something here
}, vecA, vecB, vecC, vecD, vecE, vecF);
or this (using a brace-enclosed initializer list):
template<typename Func, typename T>
void foreach(Func callback, std::initializer_list<std::vector<T>> list) {
for (auto &vec : list) {
std::for_each(vec.begin(), vec.end(), callback);
}
}
foreach([](const int &i){
// do something here
}, {vecA, vecB, vecC, vecD, vecE, vecF});
or you can join vectors like here: What is the best way to concatenate two vectors? and then iterate over big vector.
I personally prefer using what is already in the STL (in the <algorithm> header) if possible. std::transform has a signature that can take two input iterators. So at least for the case of two input containers you could do:
std::transform(containerA.begin(), containerA.end(), containerB.begin(), outputContainer.begin(), [&](const auto& first, const auto& second){
return do_operation(first, second);
});
Note that the outputContainer can also be one of the input containers. But one limitation is that you cannot do a post update operation if you are modifying one of the containers in place.
The answer is here!... when C++23 comes.
#include <algorithm>
#include <forward_list>
#include <ranges>
#include <array>
#include <iostream>
int main()
{
auto foos = std::to_array({ 1, 2, 3, 4, 5 });
auto woos = std::to_array({ 6, 7, 8, 9, 10 });
auto fooswoos = std::views::zip(foos,woos);
for(auto [foo, woo] : fooswoos) {
woo += foo;
}
std::ranges::for_each(woos, [](const auto& e) { std::cout << e << '\n'; });
return 0;
}
So, what's happening?
We are constructing a special "view". This view allows us to look at containers as if they were other structures without actually doing any copying or anything like that. Using a structured binding we are able to take a reference to each aligning element per iteration and do whatever we want to it (and safely)
Check it out on compiler explorer right now!
Here is one variant
template<class ... Iterator>
void increment_dummy(Iterator ... i)
{}
template<class Function,class ... Iterator>
void for_each_combined(size_t N,Function&& fun,Iterator... iter)
{
while(N!=0)
{
fun(*iter...);
increment_dummy(++iter...);
--N;
}
}
Example usage
void arrays_mix(size_t N,const float* x,const float* y,float* z)
{
for_each_combined(N,[](float x,float y,float& z){z=x+y;},x,y,z);
}
I will start from code:
#include <iostream>
#include <vector>
using namespace std;
struct A
{
int color;
A(int p_f) : field(p_f) {}
};
int main ()
{
A la[4] = {A(3),A(5),A(2),A(1)};
std::vector<int> lv = {begin(la).color, end(la).color};//I would like to create vector from specific value from array la
for (std::vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it) std::cout << ' ' << *it;
return 0;
}
Generally I would like to create a vector from specific values from array.
As you can see la is A array and I would like to create vector containing not the whole la array, but only color.
vector(int) not vector(A), which vector{3,5,2,1}, so not A, but only int color. It can be done using in C++11 also. Thanks.
This should work.
std::vector<int> lv;
std::transform(std::begin(la), std::end(la), std::back_inserter(lv), [](const A& a){
return a.color;
});
Also here is another way:
Refactor your structure to get color from a method:
struct A
{
int color;
A(int p_f) : color(p_f) {}
int getColor() const {
return color;
}
};
In this case you may use bind:
std::transform(std::begin(la), std::end(la), std::back_inserter(lv), std::bind(&A::getColor, std::placeholders::_1));
Or you may also use std::mem_fn to method which is a bit shorter (thanks to #Piotr S.):
std::transform(std::begin(la), std::end(la), std::back_inserter(lv), std::mem_fn(&A::getColor));
Or you may use std::mem_fn to data member. In this case you don't even need to implement a getter method:
std::transform(std::begin(la), std::end(la), std::back_inserter(lv), std::mem_fn(&A::color));
Following may help:
namespace detail
{
using std::begin;
using std::end;
template <typename Container, typename F>
auto RetrieveTransformation(const Container& c, F f)
-> std::vector<std::decay_t<decltype(f(*begin(c)))>>
{
// if `F` return `const T&`, we want `std::vector<T>`,
// so we remove reference and cv qualifier with `decay_t`.
//
// That handles additionally the case of lambda
// The return type of lambda [](const std::string&s) { return s;}
// - is `const std::string` for msvc
// - is `std::string` for for gcc
// (Note that the return type rules have changed:
// see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1048)
using F_Ret = std::decay_t<decltype(f(*begin(c)))>;
std::vector<F_Ret> res;
res.reserve(std::distance(begin(c), end(c)));
for (const auto& e : c)
{
res.push_back(f(e));
}
return res;
}
}
template <typename Container, typename F>
auto RetrieveTransformation(const Container& c, F f)
-> decltype(detail::RetrieveTransformation(c, f))
{
return detail::RetrieveTransformation(c, f);
}
And then use it as
std::vector<int> lv = RetrieveTransformation(la, std::mem_fn(&A::getColor));
// or
// auto lv = RetrieveTransformation(la, [](const A&a){return a.color;});
Live Demo
C++11 provides multiple ways to iterate over containers. For example:
Range-based loop
for(auto c : container) fun(c)
std::for_each
for_each(container.begin(),container.end(),fun)
However what is the recommended way to iterate over two (or more) containers of the same size to accomplish something like:
for(unsigned i = 0; i < containerA.size(); ++i) {
containerA[i] = containerB[i];
}
Rather late to the party. But: I would iterate over indices. But not with the classical for loop but instead with a range-based for loop over the indices:
for(unsigned i : indices(containerA)) {
containerA[i] = containerB[i];
}
indices is a simple wrapper function which returns a (lazily evaluated) range for the indices. Since the implementation – though simple – is a bit too long to post it here, you can find an implementation on GitHub.
This code is as efficient as using a manual, classical for loop.
If this pattern occurs often in your data, consider using another pattern which zips two sequences and produces a range of tuples, corresponding to the paired elements:
for (auto& [a, b] : zip(containerA, containerB)) {
a = b;
}
The implementation of zip is left as an exercise for the reader, but it follows easily from the implementation of indices.
(Before C++17 you’d have to write the following instead:)
for (auto&& items : zip(containerA, containerB))
get<0>(items) = get<1>(items);
i wonder why no one mentioned this:
auto itA = vectorA.begin();
auto itB = vectorB.begin();
while(itA != vectorA.end() || itB != vectorB.end())
{
if(itA != vectorA.end())
{
++itA;
}
if(itB != vectorB.end())
{
++itB;
}
}
PS: if the container sizes don't match, then you may need to put each container specific code into its corresponding if block.
For your specific example, just use
std::copy_n(contB.begin(), contA.size(), contA.begin())
For the more general case, you can use Boost.Iterator's zip_iterator, with a small function to make it usable in range-based for loops. For most cases, this will work:
template<class... Conts>
auto zip_range(Conts&... conts)
-> decltype(boost::make_iterator_range(
boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))))
{
return {boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))};
}
// ...
for(auto&& t : zip_range(contA, contB))
std::cout << t.get<0>() << " : " << t.get<1>() << "\n";
Live example.
However, for full-blown genericity, you probably want something more like this, which will work correctly for arrays and user-defined types that don't have member begin()/end() but do have begin/end functions in their namespace. Also, this will allow the user to specifically get const access through the zip_c... functions.
And if you're an advocate of nice error messages, like me, then you probably want this, which checks if any temporary containers were passed to any of the zip_... functions, and prints a nice error message if so.
There are a lot of ways to do specific things with multiple containers as provided in the algorithm header. For instance, in the example you've given, you could use std::copy instead of an explicit for loop.
On the other hand, there isn't any built-in way to generically iterate multiple containers other than a normal for loop. This isn't surprising because there are a lot of ways to iterate. Think about it: you could iterate through one container with one step, one container with another step; or through one container until it gets to the end then start inserting while you go through to the end of the other container; or one step of the first container for every time you completely go through the other container then start over; or some other pattern; or more than two containers at a time; etc ...
However, if you wanted to make your own "for_each" style function that iterates through two containers only up to the length of the shortest one, you could do something like this:
template <typename Container1, typename Container2>
void custom_for_each(
Container1 &c1,
Container2 &c2,
std::function<void(Container1::iterator &it1, Container2::iterator &it2)> f)
{
Container1::iterator begin1 = c1.begin();
Container2::iterator begin2 = c2.begin();
Container1::iterator end1 = c1.end();
Container2::iterator end2 = c2.end();
Container1::iterator i1;
Container2::iterator i2;
for (i1 = begin1, i2 = begin2; (i1 != end1) && (i2 != end2); ++it1, ++i2) {
f(i1, i2);
}
}
Obviously you can make any kind of iterations strategy you want in a similar way.
Of course, you might argue that just doing the inner for loop directly is easier than writing a custom function like this ... and you'd be right, if you are only going to do it one or two times. But the nice thing is that this is very reusable. =)
In case when you need to iterate simultaneously over 2 containers only, there is an extended version of standard for_each algorithm in boost range library, e.g:
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/bind.hpp>
#include <boost/range/algorithm_ext/for_each.hpp>
void foo(int a, int& b)
{
b = a + 1;
}
int main()
{
std::vector<int> contA = boost::assign::list_of(4)(3)(5)(2);
std::vector<int> contB(contA.size(), 0);
boost::for_each(contA, contB, boost::bind(&foo, _1, _2));
// contB will be now 5,4,6,3
//...
return 0;
}
When you need to handle more than 2 containers in one algorithm, then you need to play with zip.
another solution could be capturing a reference of the iterator of the other container in a lambda and using post increment operator on that. for example simple copy would be:
vector<double> a{1, 2, 3};
vector<double> b(3);
auto ita = a.begin();
for_each(b.begin(), b.end(), [&ita](auto &itb) { itb = *ita++; })
inside lambda you can do whatever with ita and then increment it. This easily extends to the multiple containers case.
A range-library provides this and other very helpful functionality. The following example uses Boost.Range. Eric Niebler's rangev3 should be a good alternative.
#include <boost/range/combine.hpp>
#include <iostream>
#include <vector>
#include <list>
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& i: boost::combine(v, l))
{
int ti;
char tc;
boost::tie(ti,tc) = i;
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
C++17 will make this even better with structured bindings:
int main(int, const char*[])
{
std::vector<int> const v{0,1,2,3,4};
std::list<char> const l{'a', 'b', 'c', 'd', 'e'};
for(auto const& [ti, tc]: boost::combine(v, l))
{
std::cout << '(' << ti << ',' << tc << ')' << '\n';
}
return 0;
}
I'm a bit late too; but you can use this (C-style variadic function):
template<typename T>
void foreach(std::function<void(T)> callback, int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
std::vector<T> v = va_arg(args, std::vector<T>);
std::for_each(v.begin(), v.end(), callback);
}
va_end(args);
}
foreach<int>([](const int &i) {
// do something here
}, 6, vecA, vecB, vecC, vecD, vecE, vecF);
or this (using a function parameter pack):
template<typename Func, typename T>
void foreach(Func callback, std::vector<T> &v) {
std::for_each(v.begin(), v.end(), callback);
}
template<typename Func, typename T, typename... Args>
void foreach(Func callback, std::vector<T> &v, Args... args) {
std::for_each(v.begin(), v.end(), callback);
return foreach(callback, args...);
}
foreach([](const int &i){
// do something here
}, vecA, vecB, vecC, vecD, vecE, vecF);
or this (using a brace-enclosed initializer list):
template<typename Func, typename T>
void foreach(Func callback, std::initializer_list<std::vector<T>> list) {
for (auto &vec : list) {
std::for_each(vec.begin(), vec.end(), callback);
}
}
foreach([](const int &i){
// do something here
}, {vecA, vecB, vecC, vecD, vecE, vecF});
or you can join vectors like here: What is the best way to concatenate two vectors? and then iterate over big vector.
I personally prefer using what is already in the STL (in the <algorithm> header) if possible. std::transform has a signature that can take two input iterators. So at least for the case of two input containers you could do:
std::transform(containerA.begin(), containerA.end(), containerB.begin(), outputContainer.begin(), [&](const auto& first, const auto& second){
return do_operation(first, second);
});
Note that the outputContainer can also be one of the input containers. But one limitation is that you cannot do a post update operation if you are modifying one of the containers in place.
The answer is here!... when C++23 comes.
#include <algorithm>
#include <forward_list>
#include <ranges>
#include <array>
#include <iostream>
int main()
{
auto foos = std::to_array({ 1, 2, 3, 4, 5 });
auto woos = std::to_array({ 6, 7, 8, 9, 10 });
auto fooswoos = std::views::zip(foos,woos);
for(auto [foo, woo] : fooswoos) {
woo += foo;
}
std::ranges::for_each(woos, [](const auto& e) { std::cout << e << '\n'; });
return 0;
}
So, what's happening?
We are constructing a special "view". This view allows us to look at containers as if they were other structures without actually doing any copying or anything like that. Using a structured binding we are able to take a reference to each aligning element per iteration and do whatever we want to it (and safely)
Check it out on compiler explorer right now!
Here is one variant
template<class ... Iterator>
void increment_dummy(Iterator ... i)
{}
template<class Function,class ... Iterator>
void for_each_combined(size_t N,Function&& fun,Iterator... iter)
{
while(N!=0)
{
fun(*iter...);
increment_dummy(++iter...);
--N;
}
}
Example usage
void arrays_mix(size_t N,const float* x,const float* y,float* z)
{
for_each_combined(N,[](float x,float y,float& z){z=x+y;},x,y,z);
}