c+모방 함수 와 함수 어댑터 의 사용 에 대한 상세 한 설명

이른바 모방 함수(functor)는 과부하()연산 자 를 통 해 함수 형 을 모 의 하 는 클래스 입 니 다.  
따라서 여기 에는 명확 한 두 가지 가 필요 하 다.
1.모방 함 수 는 함수 가 아니 라 클래스 입 니 다.  
2.모방 함수 가()연산 자 를 다시 불 러 와 서 함수 처럼 호출 할 수 있 습 니 다.  
for_each
여기 for 순환 문 구 는 좀 지루 해서 std::for 가 생각 났 습 니 다.each,for 를 사용 하기 위해each,우 리 는 함 수 를 정의 해 야 합 니 다.다음 과 같 습 니 다.

void print( State* pstate )
{
 pstate->print();
}
그래서 다음 코드 로 간략화 할 수 있 습 니 다.
std::for_each( vect.begin(), vect.end(), &print );
STL 은 크게 용기(container),알고리즘(algorithm),교체 기(iterator),모방 함수(functor),어댑터(adapter),설정 기(allocator)로 나 뉜 다.그 중에서 모방 함 수 는 부피 가 가장 작고 관념 이 가장 간단 하지만 stl 알고리즘 의 조합 에서 매우 중요 한 역할 을 하 는데 이것 은 간단 한 lambda 나 지침 함수 와 다르다.
stl 에서 plus,minus,multiplies,divides,modulus,equal 와 같은 유용 한 모방 함 수 를 대량으로 제공 합 니 다.to,not_equal_to,greater...많 습 니 다.들 어 오 는 매개 변수의 개수 에 따라 하나의 매개 변 수 를 받 아들 여야 하 는 모방 함수(unaryfunction)과 두 개의 인 자 를 받 아야 하 는 모방 함수(binaryfunction)。
모방 함수 구현 예시

//   1,    template<typename T> struct comp
{
 bool operator()(T in1, T in2) const
 {
  return (in1>in2);
 }
};comp<int> m_comp_objext;
cout << m_comp_objext(6, 3) << endl;  //      
cout << comp<int>()(1, 2) << endl;  //       
위의 코드 에서 첫 번 째 호출 방식 은 cop 가 정의 한 대상 을 사용 한 다음 에 이 대상 을 통 해 조작 자()를 호출 하여 두 배열 의 비 교 를 실현 하 는 것 입 니 다.두 번 째 호출 cop()(1,2)는 임시(이름 없 는)대상 이 생 긴 다.
2.2 모방 함수 상세 설명
아래 의 사용 장면(한 용기 의 규정 에 부합 되 는 요 소 를 통계)에서 앞서 언급 한 함수 포인터 가 왜 STL 에서 모방 함 수 를 교체 할 수 없 는 지 설명 합 니 다.

bool my_count(int num)
{
 return (num < 5);
}int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int> v_a(a, a+10);
cout << "count: " << std::count_if(v_a.begin(), v_a.end(), my_count);
위 에서 우 리 는 함수 지침 을 count 로 전달 했다.if 의 비교 조건.그러나 이 제 는 새로운 수요 에 따라 용기 에 있 는 5 이하 의 변수 개 수 를 집계 하지 않 고 8 또는 3 으로 바 꾸 었 다.그렇다면 가장 직접적인 방법 은 매개 변수 threshold 를 추가 하면 됩 니 다.아래 처럼.

bool my_count(int num, int threshold)
{
 return (num < threshold));
}
그러나 이러한 표기 법 STL 에 서 는 사용 할 수 없 으 며,용기 에 있 는 요소 의 종류 가 바 뀌 었 을 때 사용 할 수 없 으 며,더욱 중요 한 것 은 템 플 릿 함 수 를 사용 할 수 없다 는 것 이다.
그러면 다 중 전달 매개 변 수 를 사용 할 수 없 는 이상 전달 해 야 할 매개 변 수 를 전체적인 변수 로 설정 하면 현재 상황 에서 한도 값 조건 에 대한 수정 을 실현 할 수 있 지만 수정 할 때 위험 이 존재 합 니 다(초기 화 되 지 않 으 면 호출 하면 어떻게 합 니까?).그래서 이런 문 제 를 해결 하 는 방식 은
방식 이 STL 과 잘 호 환 되 었 습 니 다.

template<typename T> struct my_count1
{
 my_count1(T a)
 {
  threshold = a;
 }
 T threshold;
 bool operator()(T num)
 {
  return (num < threshold);
 }
};int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int> v_a(a, a+10);cout << "count: " << std::count_if(v_a.begin(), v_a.end(), my_count1<int>(8));
1.모방 함 수 를 정렬 기준 으로 한다.

#include <iostream>
#include <string>
#include <set>
#include <algorithm>
using namespace std;class Person
{
public:
 Person(string a, string b) :
  strFirstname(a), strLastname(b)
 {}
public:
 string firstname() const
 {
  return strFirstname;
 }
 string lastname() const
 {
  return strLastname;
 }
private:
 const string strFirstname;
 const string strLastname;
};//          
class PersonSortCriterion
{
public:
 //   
 //     :  lastname    ,lastname    firstname    
 bool operator()(const Person &p1, const Person &p2)
 {
  return (p1.lastname() > p2.lastname() ||
   ((p2.lastname() <= p1.lastname()) &&
    p1.firstname() > p2.firstname()));
 }
};
int main(int argc, char *argv[])
{
 //     ,       
 typedef set<Person, PersonSortCriterion> PersonSet;
 PersonSet col1;
 //    ,      
 Person p1("Jay", "Chou");
 Person p2("Robin", "Chou");
 Person p3("Robin", "Lee");
 Person p4("Bob", "Smith");
 //        
 col1.insert(p1);
 col1.insert(p2);
 col1.insert(p3);
 col1.insert(p4);
 PersonSet::iterator pos;
 //  PersonSet      
 for (pos = col1.begin(); pos != col1.end(); ++pos)
 {
  cout << pos->firstname() << " " << pos->lastname() << endl;
 }
 cout << endl;
 system("pause");
 return 0;
}

여러 가지 상태의 모방 함수 가 있다

#include <iostream>
#include <list>
#include<algorithm>
using namespace std;class IntSequence
{
private:
 int value;  //           
public:
 IntSequence(int initialValue) : value(initialValue)
 {
 }
 //   
 int operator()()
 {
  return value++;
 }
};int main()
{
 list<int> col1;
 //     9   ,     col1     
 generate_n(back_inserter(col1),
  9,
  IntSequence(1));
 //1 2 3 4 5 6 7 8 9 
 for (auto t : col1) {
  cout << t << " ";
 }
 cout << endl;
 //  col1    2     2 , 42  
 generate(++col1.begin(),
  --col1.end(),
  IntSequence(42));
 //1 42 43 44 45 46 47 48 9
 for (auto t : col1) {
  cout << t << " ";
 }
 cout << endl;
 system("pause");
 return 0;
}

모방 함 수 는 모두 전 달 된 값 이지 전 달 된 주소 가 아니다.따라서 알고리즘 은 매개 변수 에 따 른 모방 함수 의 상 태 를 바 꾸 지 않 습 니 다.
예 를 들 면:

IntSequence seq(1); // 1     
// 1     col1   9   
generate_n(back_inserter(col1), 9, seq);
//   1     col1   9   
generate_n(back_inserter(col1), 9, seq);
generate 함수

#include <iostream>
#include <algorithm>
#include <array>
#include <vector>
#include <functional>
using namespace std;
int main(){
 array<int,8> t1; //     100     
 generate(t1.begin(),t1.end(),[](){return rand()%100;}); //  5 1000     
 generate_n(t1.begin(),5,[](){return rand()%1000;});
 for_each(t1.begin(),t1.end(),[](int i){cout<<i<<endl;});
 return 0;
}
물론 상술 한 모방 함수 내부 상 태 를 변화 시 키 는 문 제 를 해결 하 는 방법 도 있다.
방법 은 두 가지 가 있다.
1.인용 방식 으로 모방 함 수 를 전달한다.
2,운용 foreach()알고리즘 의 반환 값.
왜냐하면 foreach()알고리즘 은 모방 함 수 를 되 돌려 줍 니 다.즉,우 리 는 반환 값 을 통 해 모방 함수 의 상 태 를 얻 을 수 있다.
인용 방식 으로 모방 함 수 를 전달 하 다.

#include <iostream>
#include <list>
#include <algorithm>using namespace std;class IntSequence
{
private:
 int value;
public:
 IntSequence(int initValue) : value(initValue)
 {} int operator()()
 {
  return value++;
 }
};int main()
{
 list<int> col1;
 IntSequence seq(1);
 //      
 generate_n<back_insert_iterator<list<int> >,
  int, IntSequence&>(back_inserter(col1),
   4,
   seq);
 //1 2 3 4;
 for (auto t : col1) {
  cout << t << " ";
 }
 cout << endl;
 //            42    4   
 generate_n(back_inserter(col1),
  4,
  IntSequence(42));
 //1 2 3 4; 42 43 44 45 
 for (auto t : col1) {
  cout << t << " ";
 }
 cout << endl;
 //          ,  seq           
 //         5  
 //  :              
 generate_n(back_inserter(col1),
  4,
  seq);
 //1 2 3 4; 42 43 44 45; 5 6 7 8 
 for (auto t : col1) {
  cout << t << " ";
 }
 cout << endl;
 //             ,       5     
 generate_n(back_inserter(col1),
  4,
  seq);
 //1 2 3 4; 42 43 44 45; 5 6 7 8; 5 6 7 8   
 for (auto t : col1) {
  cout << t << " ";
 }
 cout << endl;
 system("pause");
 return 0;
}

운용 foreach()알고리즘 의 반환 값

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;class MeanValue
{
private:
 long num;
 long sum;
public:
 MeanValue() : num(0), sum(0)
 {}
 void operator() (int elem)
 {
  num++;
  sum += elem;
 } double value()
 {
  return static_cast<double>(sum) / static_cast<double>(num);
 }
};
class Meansum
{
private:
 //long num;
 long sum;
public:
 Meansum() : sum(0)
 {}
 void operator() (int elem)
 {  sum += elem;
 } double value()
 {
  return sum;
 }
};
int main()
{
 vector<int> col1;
 for (int i = 1; i <= 8; ++i)
 {
  col1.push_back(i);
 }
 for (auto t : col1) {
  cout << t << " ";
 }
 cout << endl;
 MeanValue mv = for_each(col1.begin(), col1.end(), MeanValue());
 Meansum sum = for_each(col1.begin(), col1.end(), Meansum());
 cout << "Mean Value: " << mv.value() << endl;
 cout << "Mean sum: " << sum.value() << endl;
 system("pause");
 return 0;
}

판단 식 과 모방 함수
판단 식 은 불 형의 함수 나 모방 함 수 를 되 돌려 주 는 것 이다.STL 의 경우 불 값 을 되 돌려 주 는 모든 함수 가 합 법 적 인 판단 식 은 아니다.이것 은 다음 과 같은 의외 의 행동 을 많이 초래 할 수 있다.

#include <iostream>
#include <list>
#include <algorithm>
using namespace std;class Nth
{
private:
 int nth;
 int count;
public:
 Nth(int n) : nth(n), count(0)
 {
 }
 bool operator() (int)
 {
  return ++count == nth;
 }
};
int main()
{
 list<int> col1;
 for (int i = 1; i <= 9; ++i)
 {
  col1.push_back(i);
 }
 //1 2 3 4 5 6 7 8 9
 for (auto t : col1) {
  cout << t << " ";
 }
 cout << endl; list<int>::iterator pos;
 pos = remove_if(col1.begin(), col1.end(), Nth(3));
 col1.erase(pos, col1.end());
 for (auto t : col1) {
  cout << t << " ";
 }
 cout << endl;
 system("pause");
}

함수 어댑터(함수 어댑터)
함수 어댑터:모방 함수 와 다른 모방 함수(또는 특정한 값,또는 특정한 일반 함수)를 결합 시 킬 수 있 는 모방 함수.
함수 어댑터 는 헤더 파일에 포함 되 어 있 습 니 다.미리 정 의 된 함수 어댑터 는 다음 표 와 같 습 니 다.

먼저 몇 가지 개념,무엇이 일원 함수,이원 함수 인지 확실히 알 아 라.
1.일원 함수 매개 변수
2.이원 함수 두 개의 매개 변수
3.1 원 술어 의 매개 변 수 는 bool 형 으로 되 돌아 갑 니 다.
4.이원 서술 어 두 개의 매개 변 수 는 bool 형 으로 되 돌아 갑 니 다.
함수 어댑터 는 한 함수 대상 이 다른 유형의 함수 대상 을 나타 내 도록 하 는 특징 이다.많은 경우 에 우리 가 가지 고 있 는 함수 대상 이나 일반 함수 의 매개 변수 개수 나 반환 값 유형 은 우리 가 원 하 는 것 이 아니 기 때문에 함수 어댑터 가 우리 의 함수 에 적합 해 야 합 니 다.
C++에는 용기 어댑터,교체 기 어댑터,함수 어댑터 등 세 가지 어댑터 가 있 습 니 다.함수 어댑터 를 소개 합 니 다.
함수 어댑터 는 1 원 2 원 함수 대상 을 특 화하 고 확장 하 는 데 사용 되 며 함수 어댑터 는 주로 다음 과 같은 두 가지 종류 가 있 습 니 다.
1 귀속 기
이 종류의 어댑터 는 이원 함 수 를 일원 함수 로 맞 추 는 데 쓰 인 다
이원 함수 의 매개 변 수 를 특정한 값 에 연결 하여 이원 함수 대상 을 일원 함수 대상 으로 변환 합 니 다.
바 인 딩 기 어댑터 는 두 가지 가 있 습 니 다.bid1st bid2nd.바 인 딩 기 마다 함수 대상 과 값 을 받 습 니 다.
bind1st 는 주어진 값 을 이원 함수 대상 의 첫 번 째 실제 인삼 에 연결 합 니 다.
bind2nd 는 주어진 값 을 이원 함수 대상 의 두 번 째 실제 인삼 에 연결 합 니 다.

#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>using namespace std;bool is_odd(int n)
{
 return n % 2 == 1;
}int main(void)
{
 int a[] = { 1, 2, 3, 4, 5 };
 vector<int> v(a, a + 5); cout << count_if(v.begin(), v.end(), is_odd) << endl;
 //         
 //    bind2nd       modulus         。
 //bind2nd(op, value) (param)   op(param, value)
 cout << count_if(v.begin(), v.end(),bind2nd(modulus<int>(), 2)) << endl; //bind1st(op, value)(param)   op(value, param);
 // 4        ,  4 < value
 // 4       
 cout << count_if(v.begin(), v.end(),bind1st(less<int>(), 4)) << endl; // 3        ,  value < 3
 // 3       
 cout << count_if(v.begin(), v.end(), bind2nd (less<int>(), 3)) << endl; // 3        ,  value < 3
 //not1         。
 //            
 // 3            
 cout << count_if(v.begin(), v.end(),not1( bind2nd (less<int>(), 3)) )<< endl;
 system("pause");
 return 0;
 //   3 3 1 2 3
}
이상 은 개인 적 인 경험 이 므 로 여러분 에 게 참고 가 되 기 를 바 랍 니 다.여러분 들 도 저 희 를 많이 응원 해 주시 기 바 랍 니 다.잘못 이 있 거나 완전히 고려 되 지 않 은 곳 이 있 으 면 댓 글 토론 을 환영 합 니 다.아 낌 없 는 가르침 을 바 랍 니 다.

좋은 웹페이지 즐겨찾기