Passing an array using for_each loop

Pages: 12
Hello there!

I am learning lambda functions. Is it possible to pass an array into a vector using for_each loop and then print concurrently?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream> // std::cout
#include <algorithm> // std::for_each
#include <vector> //std::vector
#include <string> //std::string

int main(){
  std::vector<std::string> pokemon;

  /*
  Traditional way of adding a vector element
  */
  pokemon.push_back("Pikachu"); //adds "Pikachu" to the vector
  pokemon.push_back("Charmander"); //adds "Charmander" to the vector
  pokemon.push_back("Squirtle"); //adds "Squirtle" to the vector
  
  /*
  Traditional way of printing each vector element without using a typical for loop
  REMEMBER: vector elements are zero-indexed
  */
  std::cout << "Traditional std::vector() printing:" << std::endl;
  std::cout << pokemon[0] << std::endl; //prints "Pikachu"
  std::cout << pokemon[1] << std::endl; //prints "Charmander"
  std::cout << pokemon[2] << std::endl; //prints "Squirtle"
  std::cout << std::endl;
  


  /*
  Passing an array by utilizing vector::insert()
  */
  
  //HERE IS WHERE I NEED HELP
  std::string pokemon_to_add[3] = {"Butterfree", "Onyx", "Arbok"};
  pokemon.insert(pokemon.end(), pokemon_to_add, pokemon_to_add + 3);

  //I reckon it would be something like:
  //for_each(pokemon.begin(), pokemon.end(), [](const auto &i){push_back(i);});


  /*
  Printing vector elements using for_each loop
  NOTE: auto is not allowed in a lambda parameter
  C++14 support or later is required
  */
  std::cout << "For_each std::vector() printing:" << std::endl;
  for_each(
    pokemon.begin(), //InputIterator first
    pokemon.end(), //InputIterator last
    [](const auto &i) {std::cout << i << std::endl;} //Function fn
  ); //prints from index 0 to the vector size -1
}
Last edited on


edit, nm now i see what the issue is.

ya idk if its possible without doing some funky stuff. The issue is that an array of strings is the equivalent of an array of vector<char> and the iterators (as far as i can tell only point to individual elements or chars as opposed to the whole vector.

it can easily be done with a vector of strings instead of an array.

1
2
3
4
	vector<string> st{};
	vector<string> a{ "abc" , "123", "easy" };
	
	for_each(a.begin(), a.end(), [&st](const auto &i) {st.push_back(i); cout << i; });


i suppose something like this is possible but the issue becomes that the looping of the iterator is pointless and has no way to determine the size of the array. The only reason it works is bc theyre the same size.

1
2
3
4
5
6

vector<string> st{"","",""};
	string a[3]{ "abc" , "123", "easy" };
	int x = 0;
	
	for_each(st.begin(), st.end(), [&st, &x, a](const auto &i) {st.push_back(a[x]); x++; cout << st.back(); });


i guess it just depends on how far you want to take it, but starts to get unreadable in a hurry

 
for_each(st.begin(), st.end(), [&st, &x, &a](const auto& i) {if (x < sizeof(a)/sizeof(string)) { st.push_back(a[x]); x++; cout << st.back(); } }); 
Last edited on
thanks for your response, markyrocks

i see that passing a vector into another is a much easier task opposed to string array into a vector when using for_each loop. otherwise, I'll just have to stick with a typical for loop.

going off of your example:

1
2
3
4
5
6
std::cout << "Appending and then printing std::vector using for_each loop:" << std::endl;  
std::vector<std::string> pokemon_to_add {"Butterfree", "Onyx", "Arbok"};
for_each(pokemon_to_add.begin(), pokemon_to_add.end(), [&](const auto &i) {
    pokemon.push_back(i);
    std::cout << i << std::endl;
  });



Appending and then printing std::vector using for_each loop:
Butterfree
Onyx
Arbok


since we're passing in the new vector from vector std::begin() to std::end() into the original vector, it only prints the new elements, right? which also means that i'd have to create a new loop to print the old + new elements?

i reckon should we switch the vector placements, it'd print the original and its appended elements:

1
2
3
4
5
6
std::cout << "Appending and then printing std::vector using for_each loop:" << std::endl;  
std::vector<std::string> pokemon_to_add {"Butterfree", "Onyx", "Arbok"};
for_each(pokemon.begin(), pokemon.end(), [&](const auto &i) {
    pokemon_to_add.push_back(i);
    std::cout << i << std::endl;
  });



Appending and then printing std::vector using for_each loop:
Pikachu
Charmander
Squirtle


it still doesn't print the appended elements :'c
Last edited on
Mind-boggling.

The std::for_each http://www.cplusplus.com/reference/algorithm/for_each/ is a convenience algorithm.
You can hide/reuse the body of a loop with it:
1
2
for_each( myvector.begin(), myvector.end(), somethingcomplex );
for_each( a, a+5, somethingcomplex );

It is clear and compact that something is done for/with those arrays.

Alas, you obviously have to consult the implementation of 'somethingcomplex' to know what those loops do.

The lambda allows you write the body of somethingcomplex in place. That does not quite make sense with for_each.
1
2
3
4
5
6
7
8
9
10
11
12
13
void somethingcomplex(T e) {
  // 100 lines
}

for_each( myvector.begin(), myvector.end(), somethingcomplex );
// OR
for( auto it = myvector.begin(); it != myvector.end(), ++it ) {
  // 100 lines
}
// OR
for_each( myvector.begin(), myvector.end(), [](T e) {
  // 100 lines
} );


Lambdas appeared in C++11. So did ranged for-syntax.
The latter is syntactic sugar for repeating operation for each element in array/container.
You can still use your functor to hide the body:
1
2
3
for ( auto e : myvector ) {
  somethingcomplex( e );
}


However, simple stuff can be there directly:
1
2
3
4
5
6
for ( auto p : pokemon_to_add ) {
  pokemon.push_back( p );
}
for ( auto p : pokemon ) {
  std::cout << p << '\n';
}


There is an additional benefit in the insert(): addition of multiple elements may cause reallocation in the vector and in worst case multiple times. The insert() can do pre-emptive reallocation.
Therefore, you should really compare:
1
2
3
4
5
6
pokemon.insert(pokemon.end(), pokemon_to_add, pokemon_to_add + 3);
// with
pokemon.reserve( pokemon.size() + 3 );
for ( auto p : pokemon_to_add ) {
  pokemon.push_back( p );
}
You can use the std::begin()/std::cbegin()/std::end()/std::cend() member functions. They work on regular arrays and retrieve iterators (actually pointers) to the first and past-the-last elements, respectively.
I think you guys are missing the point that he's attempting to use the for each loop to push an array of strings into an existing vector. Ideally you want the array to be the subject of the for each loop but theres no way to iterate though it bc you can't retrieve an iterator that contains the entire element and move to the end etc. You can only retrieve iterators that point to individual chars inside the string. At least thats the conclusion I've come to anyways. Even if you pass the vector that you're attempting to push into to the lambda via the parameter, i wasn't able to reverse the iterator to point back to the vector as a whole. Outside of the lambda like in main i could do like

auto it = vec.begin();
Int a =0;

it._Ptr.push_back(a); // it may need dereferenced here i forget.

Wasn't entirely sure that was successful but I believe ive used that in the past. Or at least something similar.
it._Ptr.push_back(a); // it may need dereferenced here i forget.
You shouldn't be using any "_CapitalLetter" members, they are reserved as implementation details. I don't exactly understand what's happening in this thread, but I assure you there's a better way to do it than using _Ptr or other internal library stuff.
Last edited on
I'm pretty sure that the OP's question is primarily about C++'s somewhat peculiar lambda abstraction.
1
2
for_each(pokemon_to_add, pokemon_to_add + 3, 
  [&pokemon](const auto &i) { pokemon.push_back(i); });

Last edited on
i reckon should we switch the vector placements, it'd print the original and its appended elements:
1
2
3
4
5
6
7
std::vector<std::string> pokemon_to_add {"Butterfree", "Onyx", "Arbok"};

for_each( pokemon.begin(), pokemon.end(),
  [&](const auto &i) {
    pokemon_to_add.push_back(i);
    std::cout << i << std::endl;
  });

it still doesn't print the appended elements

You call function for_each(). It takes copies of values:
1
2
3
InputIterator first = pokemon.begin();
InputIterator last  = pokemon.end();
Function fn = lambda;

That iterates elements of pokemon {Pikachu, Charmander, Squirtle}.
Luckily you don't modify the pokemon within the lambda. That could invalidate iterators to pokemon.

The iteration appends elements of pokemon into pokemon_to_add. That operation has no effect on pokemon.
You effectively do:
1
2
3
4
5
auto first = pokemon.begin();
while ( first != pokemon.end() ) {
  std::cout << *first << std::endl;
  ++first;
}

Why are you surprised that this code prints only the contents of pokemon?

I think you guys are missing the point that he's attempting to use the for each loop to push an array of strings into an existing vector. Ideally you want the array to be the subject of the for each loop but theres no way to iterate though it bc you can't retrieve an iterator that contains the entire element and move to the end etc. You can only retrieve iterators that point to individual chars inside the string. At least thats the conclusion I've come to anyways.


That's false.
1
2
std::for_each(std::cbegin(pokemon_to_add), std::cend(pokemon_to_add), 
                                  [&pokemon](auto&& i){pokemon.push_back(i)});


Though it would be better to just use std::copy with a back_insert_iterator
Last edited on
thanks for replying, people.

i was assigned to write a sample code where i utilize for_each loop instead of a traditional for loop so i thought i'd do the above. the code also has to be beginner-friendly.

i am attempting to append strings into an existing vector and then print using one loop

I've tried multiple approaches in appending a new vector in an already existing vector and then printing in just one loop.

the appendment is always successful, but when it gets to printing: either the already existing vector prints or what's inside of the vector that's to be appended but never both... does that make sense?

It should be a two-step process. Add the stuff to the vector, then print the vector.
1
2
3
4
for_each(pokemon_to_add, pokemon_to_add + 3, 
  [&pokemon](const auto &i) { pokemon.push_back(i); });
for_each(pokemon.begin(), pokemon.end(), 
  [](const auto &p) { std::cout << p << '\n'; });
It should be a two-step process. Add the stuff to the vector, then print the vector.


I mean, it could be done in a single lambda, couldn't it?
1
2
3
4
5
6
7
8
9
10
11
int main()
{
    int arr[5] = {1,2,3,4,5};
    std::vector<int> vec;
    std::for_each(std::cbegin(arr), std::cend(arr), 
            [&vec](auto&& i){
                vec.push_back(i);
                std::cout << vec.back() << " ";
                //Or std::cout << i << " ";
            });
}


Assuming OP wants to add to the empty vector and immediately print it out like in the example you gave.
Last edited on
Have you tested this? I only ask bc idk how its possible to use an iterator on something that isn't of type vector.

If so waaaa waaaaa I'm wrong. Lol. Not home rn so can't test it.


http://cpp.sh/3uwrp

Says cbegin not a member of std. Also cbegin take 0 parameters id assume cend aswell.
Last edited on
Have you tested this? I only ask bc idk how its possible to use an iterator on something that isn't of type vector.


An iterator could be anything that acts like an iterator. Thus, a regular pointer is also an iterator. std::iterator_traits has a partial specialization for raw pointer types:
https://en.cppreference.com/w/cpp/iterator/iterator_traits#T.2A_specialization_member_types

So technically speaking, a T* (for a type T) is a random-access-iterator.

Given this fact, if we have the following array:
std::string pokemon_to_add[3] = {"Butterfree", "Onyx", "Arbok"};

We could obtain iterators to the beginning and end by doing raw pointer arithmetic using the std::string*s, like mbozzi explains:

1
2
std::string* begin_iterator = pokemon_to_add ;//First element
std::strong* end_iterator = pokemon_to_add + 3 ;//Past-the-last element 


Or you can use the more generic method:

1
2
auto begin_iterator = std::cbegin(pokemon_to_add); //First element
auto end_iterator = std::cend(pokemon_to_add); //Past-the-last element 


Either case will work. Dereferencing the begin_iterator will produce the std::string "Butterfree". Dereferencing the end_iterator is garbage (as expected).
Last edited on
<removed dumb post>
Last edited on
Says cbegin not a member of std.


That website only supports up to C++14. You need to compile with C++17 in order to use std::cbegin().

https://onlinegdb.com/BySf5KSsU

Also cbegin take 0 parameters id assume cend aswell.


Not the global functions:
https://en.cppreference.com/w/cpp/iterator/begin
Last edited on
You need to compile with C++17 in order to use std::cbegin().

cppreference indicates std::cbegin/std::cend are C++14 or later.
https://en.cppreference.com/w/cpp/iterator/begin

C++ Shell should compile and run that code sample. Clearly their library implementation is not accurate.
Well ain't that a daisy. Useful ty.
Coliru (compile, link and run) is another online compiler that runs under GCC 9.2.
http://coliru.stacked-crooked.com/

If you want to edit and run code without the need to see what machine code is generated it is a site I'd recommend.
Pages: 12