for_ How to use each

Abstract
Before (original) how to use for_each() algorithm? (C/C++) (STL)   Once discussed for_each(), but at that time, my skills were still shallow. I only talked about the fur. After reading items 41 and 43 of effective STL this time, I was right about for_each() has a deeper understanding, so this experience report is made.

Motivation
I saw the of eXile Implementing foreach in C + + Macro is used to improve foreach, and many people's opinions on STL style for_each() makes me want to discuss the for of STL_ Each () did another study.

Introduction
After learning the STL container, you must have written the following program to access each iterator  

#include <vector>
#include <iostream>

using namespace std;

int main() 
{
  int ia[] = {1, 2, 3};
  vector<int> ivec(ia, ia + sizeof(ia) / sizeof(int));
  
  for(vector<int>::const_iterator iter = ivec.begin(); iter != ivec.end(); ++iter) {
    cout << *iter << endl;
  }
}

Execution results

1

2

3
At that time, I thought everything about STL was good, that is, the following string was smelly and long

for(vector<int>::const_iterator iter = ivec.begin(); iter != ivec.end(); ++iter) {

If you don't write often, you won't be able to write it at the moment. In fact, if you cooperate with the container, C + + shouldn't write back the circle in this way. The correct way is to use for_ The syntax of each () will be quite simple.

for_each() is actually a function template, which is actually done as follows [effective STL item 41]

template<typename InputIterator, typename Function>
Function for_each(InputIterator beg, InputIterator end, Function f) {
  while(beg != end) 
    f(*beg++);
}

From the above source, for_each() can only work with global function and function object.

Next, we will compare procedure based, object oriented, and generic paradigm s with for_ Discuss the collocation of each ().

Procedure Based and for_ Each collocation
1. Do not pass in parameters

/* 
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename    : GenericAlgo_for_each_GlobalFunction.cpp
Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to use for_each with global function
Release     : 05/11/2007 1.0
*/
#include <iostream>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

void printElem(int& elem) {
  cout << elem << endl;
}

int main() {
  int ia[] = {1, 2, 3};
  vector<int> ivec(ia, ia + sizeof(ia) / sizeof(int));
  
  for_each(ivec.begin(), ivec.end(), printElem);
}

Execution results

1

2

3


Line 23

for_each(ivec.begin(), ivec.end(), printElem);

Just pass vector::begin(), vector::end() and global function name to for_each() is enough, and the complex syntax of for loop is no longer needed.  

2. Pass in parameters
If you want to pass parameters to global function, you can no longer just pass global function name. You must pass PTR_ The function adapter of fun () converts the global function into a function object, and then uses bind2nd() to bind the parameter into a function object.

/* 
C) OOMusou 2007 http://oomusou.cnblogs.com
ilename    : GenericAlgo_for_each_GlobalFunctionWithParameter.cpp
Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to use for_each with global function with Parameter
Release     : 05/11/2007 1.0
*/
#include <iostream>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>

using namespace std;

void printElem(int elem, const char* prefix) {
  cout << prefix << elem << endl;
}

int main() {
  int ia[] = {1, 2, 3};
  vector<int> ivec(ia, ia + sizeof(ia) / sizeof(int));
  
  for_each(ivec.begin(), ivec.end(), bind2nd(ptr_fun(printElem), "Element:"));
}

Execution results

Element:1

Element:2

Element:3


Object Oriented and for_ Each collocation
1. Do not pass in parameters
Using function object

 /* 
 C) OOMusou 2007 http://oomusou.cnblogs.com
 ilename    : GenericAlgo_for_each_FunctionObject.cpp
 Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
 Description : Demo how to use for_each with function object
 Release     : 05/11/2007 1.0
 */
 #include <iostream>
 #include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

struct printElem {
  void operator() (int elem) {
    cout << elem << endl;
  } 
};

int main() {
  int ia[] = {1, 2, 3};
  vector<int> ivec(ia, ia + sizeof(ia) / sizeof(int));
  
  for_each(ivec.begin(), ivec.end(), printElem());
}

Execution results

1

2

3


2. Pass in parameters
If you use function object, you can also pass the parameter to printelement(), and receive the parameter through the skill of constructor.

/* 
C) OOMusou 2007 http://oomusou.cnblogs.com
ilename    : GenericAlgo_for_each_FunctionObjectWithParameter.cpp
Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to use for_each with function object with parameter
Release     : 05/11/2007 1.0
*/
#include <iostream>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

struct printElem {
  const char* _prefix;

  printElem(const char* prefix) : _prefix(prefix) {}
  
  void operator() (int elem) {
    cout << _prefix << elem << endl;
  } 
};

int main() {
  int ia[] = {1, 2, 3};
  vector<int> ivec(ia, ia + sizeof(ia) / sizeof(int));
  
  for_each(ivec.begin(), ivec.end(), printElem("Element:"));
}

Execution results  
Element:1

Element:2

Element:3

There are many ways to write a function object, but as long as it is a function object, it can be followed by for_ Cooperate with each.


3.member_function and for_ Each collocation
3.1 do not pass in parameters
The focus of this article comes. In the object-oriented world, the most commonly used is for_ How to write each () with member function? Intuition will write like this

for_each(_doorVec.begin(), _doorVec.end(),&Door::open); 

Since global function name itself is a pointer, you want to pass in an address through & door:: open, but you can't compile too much. The correct solution is

for_each(_doorVec.begin(), _doorVec.end(), mem_fun_ref(&Door::open));

Through mem_fun_ref() function adapter converts member function into function object.

 

/* 
(C) OOMusou 2007 http://oomusou.cnblogs.com

Filename    : GenericAlgo_for_each_MemberFunctionObject.cpp
Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to use for_each with member function with object
Release     : 05/11/2007 1.0
*/
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>

using namespace std;

class Door {
public:
  void open() const {
    cout << "open door horizontally" << endl;
  }
  
  void close() const {
    cout << "close door horizontally" << endl;
  }
};

class DoorController {
protected:
  vector<Door> _doorVec;
  
public:
  void addDoor(Door aDoor) {
    _doorVec.push_back(aDoor);
  }
  
  void openDoor() const {
    for_each(_doorVec.begin(), _doorVec.end(), mem_fun_ref(&Door::open));
  }
};

int main() {
  DoorController dc;
  dc.addDoor(Door());
  dc.addDoor(Door());
  dc.openDoor();
}

Execution results

open door horizontally

open door horizontally


Line 37

for_each(_doorVec.begin(), _doorVec.end(), mem_fun_ref(&Door::open));

It is worth noting that mem_fun_ref() is used in the member function of the object. To match multiple types, the vector must put a pointer, that is, the member function of the object pointer must be used, and MEM must be used at this time_ Fun() converts member function to function object.

 

/* 
(C) OOMusou 2007 http://oomusou.cnblogs.com

Filename    : GenericAlgo_for_each_MemberFunctionObjectPointer.cpp
Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to use for_each with member function with object pointer
Release     : 05/11/2007 1.0
*/
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>

using namespace std;

class AbstractDoor {
public:
  virtual void open() const {
    cout << "open door horizontally" << endl;
  }
  
  virtual void close() const {
    cout << "close door horizontally" << endl;
  }
};

class HorizontalDoor : public AbstractDoor {
};

class VerticalDoor : public AbstractDoor {
public:
  void open() const {
    cout << "open door vertically" << endl;
  }
  
  void close() const {
    cout << "close door vertically" << endl;
  }
};

class DoorController {
protected:
  vector<AbstractDoor*> _doorVec;
  
public:
  void addDoor(AbstractDoor& aDoor) {
    _doorVec.push_back(&aDoor);
  }
  
  void openDoor() const {
    for_each(_doorVec.begin(), _doorVec.end(), mem_fun(&AbstractDoor::open
  }
};

int main() {
  DoorController dc;
  dc.addDoor(HorizontalDoor());
  dc.addDoor(VerticalDoor());
  dc.openDoor();
}

Execution results

open door horizontally

open door vertically


Line 51

for_each(_doorVec.begin(), _doorVec.end(), mem_fun(&AbstractDoor::open));

MEM is used_ fun().

3.2 incoming parameters
The problem comes again. What if you want member function to pass in parameters? At this time, you have to use bind2nd to combine the function object with the parameter bind to become another new function object.

/* 
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename    : GenericAlgo_for_each_MemberFunctionObjectPointerWithParameter.cpp
Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to use for_each with member function with object pointer
Release     : 05/11/2007 1.0
/
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

class AbstractDoor {
public:
  virtual void open() const {
    cout << "open door horizontally" << endl;
  }
  
  virtual void close() const {
    cout << "close door horizontally" << endl;
  }
  
  virtual void openDoorBy(const char* name) const {
    cout << name << " ";
    open();
  }
};

class HorizontalDoor : public AbstractDoor {
};

class VerticalDoor : public AbstractDoor {
public:
  void open() const {
    cout << "open door vertically" << endl;
  }
  
  void close() const {
    cout << "close door vertically" << endl;
  }
};

class DoorController {
protected:
  vector<AbstractDoor*> _doorVec;
  
public:
  void addDoor(AbstractDoor& aDoor) {
    _doorVec.push_back(&aDoor);
  }
  
  void openDoor() const {
    for_each(_doorVec.begin(), _doorVec.end(), bind2nd(mem_fun(&AbstractDo:openDoorBy), "John"));
  }
};

int main() 
{
  DoorController dc;
  dc.addDoor(HorizontalDoor());
  dc.addDoor(VerticalDoor());
  dc.openDoor();
}

Execution results

1        John open door horizontally
2        John open door vertically


56 lines

for_each(_doorVec.begin(), _doorVec.end(), bind2nd(mem_fun(&AbstractDoor::openDoorBy), "John"));

After combining the parameters through bind2nd, it becomes a new function object.

Generics and for_ Each collocation
1.Function Template
1.1 do not pass in parameters
In the generic world, that's for_ How should each () cooperate with function template?  

/* 
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename    : GenericAlgo_for_each_FunctionTemplate.cpp
Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to use for_each with function template
Release     : 05/11/2007 1.0
/
#include <iostream>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

template<typename T>
void printElem(T elem) {
  cout << elem << endl;
}

int main() {
  int ia[] = {1, 2, 3};
  vector<int> ivec(ia, ia + sizeof(ia) / sizeof(int));
  
  for_each(ivec.begin(), ivec.end(), printElem<int>);
  //for_each(ivec.begin(), ivec.end(), (void(*)(int))printElem);
}

Execution results

1

2

3


If you use function template, there are two ways to write it
One is

for_each(ivec.begin(), ivec.end(), printElem<int>);

Because the template function needs to determine the type during compile, it needs to add < int > to determine the type as int.
Another way to write  

for_each(ivec.begin(), ivec.end(), (void(*)(int))printElem);

template function does not determine the type, but when it is converted to function pointer, it must be explicitly converted to function pointer of int type.

1.2 incoming parameters
How to transfer parameters like function object? Fund template is OK, but there are some restrictions. If you use nontype parameter, you can only use the following three types
1.int or enum
2.pointer: pointer to object,pointer to function,pointer to member.
3.reference: reference to object,reference to function.  

/* 
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename    : GenericAlgo_for_each_FunctionTemplateWithNontypeParameter.cpp
Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to use for_each with function template with nontype parameter
Release     : 05/11/2007 1.0
/
#include <iostream>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

template<typename T, int i>
void printElem(T elem) {
  cout << i << ":"  << elem << endl;
}

int main() {
  int ia[] = {1, 2, 3};
  vector<int> ivec(ia, ia + sizeof(ia) / sizeof(int));
  
  for_each(ivec.begin(), ivec.end(), printElem<int, 5>);
}

Execution results

5:1

5:2

5:3


Therefore, it is impossible to pass in strings or arbitrary types like function object, at least not in the current ISO C + + standard.
Since function template is discussed, can the most powerful class template also be used with for_each()?

2.Class Template
2.1 do not pass in parameters

/* 
(C) OOMusou 2007 http://oomusou.cnblogs.com
Filename    : GenericAlgo_for_each_ClassTemplate.cpp
Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to use for_each with class template
Release     : 05/11/2007 1.0
/
#include <iostream>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>

using namespace std;

template<typename T>
class printElem : public unary_function<T, void> {
public:
  void operator() (T elem) {
    cout << elem << endl;
  }
};

int main() {
  int ia[] = {1, 2, 3};
  vector<int> ivec(ia, ia + sizeof(ia) / sizeof(int));
  
  for_each(ivec.begin(), ivec.end(), printElem<int>());
}

Execution results

1

2

3


Line 17

class printElem : public unary_function<T, void> {

Because printelement only accepts for_ The parameters passed by each () are only single parameters, so public inherits unary_ Function < T, void >, because for_ Definition of each

template <class InputIterator, class UnaryFunction>

UnaryFunction for_each(InputIterator first, InputIterator last, UnaryFunction f);


The UnaryFunction type is passed in. The first type parameter T represents the incoming type, the second type parameter void represents the returned type, and finally redefine the operator().

2.2 incoming parameters
If you want the class template to pass in parameters, you can also use the skill of function object and borrow the constructor.

/* 
(C) OOMusou 2007 http://oomusou.cnblogs.com
ilename    : GenericAlgo_for_each_ClassTemplateWithParameter.cpp
Compiler    : Visual C++ 8.0 / BCB 6.0 / gcc 3.4.2 / ISO C++
Description : Demo how to use for_each with class template & parameter
Release     : 05/11/2007 1.0
/
#include <iostream>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>

using namespace std;

template<typename T, typename U>
class printElem : public unary_function<T, void> {
private:
  U _prefix;
  
public:
  printElem(U prefix) : _prefix(prefix) {}
  
  void operator() (T elem) {
    cout << _prefix << elem << endl;
  }
};

int main() {
  int ia[] = {1, 2, 3};
  vector<int> ivec(ia, ia + sizeof(ia) / sizeof(int));
  
  for_each(ivec.begin(), ivec.end(), printElem<int, const char*>("Element:"));
}

Execution results

Element:1

Element:2

Element:3


Conclusion
STL for_each() is actually very easy to use, but it often discourages many novices due to many restrictions. This paper tries to put forward and discuss all the problems that will be encountered, including procedure based, object oriented, genetics and for_ The collocation of each () is covered. I hope it will be helpful to you.

Transferred from:   for_ How to use each - jianguo_wang - blog Park (cnblogs.com)

Tags: C++

Posted on Thu, 09 Sep 2021 15:32:04 -0400 by mndwn