함수 객체

SOEUN CHOI·2022년 6월 24일
0

C++_study

목록 보기
13/15

씹어먹는 C++

15장 함수 객체 705p-718p


Callable

( )를 붙여서 호출(call) 할 수 있는 모든 것
함수, 객체, 람다 함수 etc.

std::function

함수 뿐만이 아니라 모든 Callable 들을 보관할 수 있는 객체
템플릿 인자로 전달 받을 함수의 타입(리턴값과 함수 인자들)을 갖음
std::function<리턴값(함수인자)> [이름] = [받을 callable];

example code

#include <functional>
#include <iostream>
#include <string>

int some_func1(const std::string& a) {
  std::cout << "Func1 호출! " << a << std::endl;
  return 0;
}

struct S {
  void operator()(char c) { std::cout << "Func2 호출! " << c << std::endl; }
};

int main() {
  std::function<int(const std::string&)> f1 = some_func1;
  std::function<void(char)> f2 = S();
  std::function<void()> f3 = []() { std::cout << "Func3 호출! " << std::endl; };
  f1("hello");
  f2('c');
  f3();
}

Func1 호출! hello
Func2 호출! c
Func3 호출!

멤버 함수를 갖는 std::function

멤버 함수

  • 구현 상 자신을 호출한 객체를 인자로 암묵적으로 받음
  • 원래 인자에 추가적으로 객체를 받는 인자를 전달
  • 암시적 변환이 발생하지 않으므로 & 연산자를 통해 명시적으로 주소값을 전달
  • 호출 하려는 객체를 인자로 전달하여 해당 객체의 멤버 함수를 호출한 것 처럼 사용

example code

#include <functional>
#include <iostream>
#include <string>

class A {
  int c;
  
  public:
    A(int c) : c(c) {}
    int some_func() {
      std::cout << "비상수 함수: " << ++c << std::endl;
      return c;
    }
    int some_const_function() const {
      std::cout << "상수 함수: " << c << std::endl;
      return c;
    }
    static void st() {}
};

int main() {
  A a(5);
  std::function<int(A&)> f1 = &A::some_func;
  std::function<int(const A&)> f2 = &A::some_const_function;
  
  
  f1(a);
  f2(a);
}

비상수 함수: 6
상수 함수: 6

mem_fn

std::mem_fn

전달된 멤버 함수를 function 객체로 만들어서 리턴
즉 멤버 함수들을 함수 객체로 만들어 전달

  • 반복을 피하기 위해 사용
    인자로 전달하는 함수가 멤버 함수일때
    정확한 전달을 위해 std::function 으로 변환해서 전달 해야함
    해당 일을 반복하지 않기 위해 mem_fn 사용
  • <functional> 헤더를 추가
  • 람다 함수로도 동일한 작업을 수행 가능

example code

#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
using std::vector;

int main() {
  vector<int> a(1);
  vector<int> b(2);
  vector<int> c(3);
  vector<int> d(4);
  
  vector<vector<int>> container;
  container.push_back(a);
  container.push_back(b);
  container.push_back(c);
  container.push_back(d);
  
   vector<int> size_vec(4);
   //mem_fn을 통해 간단히 멤버 함수를 넘김
   transform(container.begin(), container.end(), size_vec.begin(),std::mem_fn(&vector<int>::size));
   /*람다 함수로도 가능
   std::mem_fn(&vector<int>::size)
   = [](const auto&v){ return v.size()}
   */
   for (auto itr = size_vec.begin(); itr != size_vec.end(); ++itr) {
   		std::cout << "벡터 크기 :: " << *itr << std::endl;
  }
}

벡터 크기 :: 1
벡터 크기 :: 2
벡터 크기 :: 3
벡터 크기 :: 4

std::bind

원래 함수에 특정 인자를 붙여(bind) 줌
함수 객체 생성 시에 인자를 특정한 것으로 지정

example code

#include <functional>
#include <iostream>

void add(int x, int y) {
  std::cout << x << " + " << y << " = " << x + y << std::endl;
}
void subtract(int x, int y) {
  std::cout << x << " - " << y << " = " << x - y << std::endl;
}
int main() {
  //add 함수의 첫번째 인자로 2를 bind
  auto add_with_2 = std::bind(add, 2, std::placeholders::_1);
  //두번째 인자로 새롭게 만들어진 함수 객체의 첫번째 인자 전달
  add_with_2(3);
  
  // 여러 인자 전달시 필요한 인자 이후는 다 무시된다.
  add_with_2(3, 4);
  
  //placeholders_1, _2 -> 일일히 정의된 객체들
  auto subtract_from_2 = std::bind(subtract, std::placeholders::_1, 2);
  auto negate = std::bind(subtract, std::placeholders::_2, std::placeholders::_1);
  
  subtract_from_2(3); // 3 - 2 를 계산한다.
  negate(4, 2); // 2 - 4 를 계산한다
}

2 + 3 = 5
2 + 3 = 5
3 - 2 = 1
2 - 4 = -2

※ 레퍼런스를 인자로 받는 함수 유의
bind 함수로 인자가 복사 되서 전달
따라서 명시적으로 레퍼런스 전달이 필요

// 명시적 레퍼런스 전달 std::ref() 사용
auto do_something_with_s1 = std::bind(do_something, std::ref(s1), std::placeholders::_1);
  • ref() 함수
    전달 받은 인자를 복사 가능한 레퍼런스로 변환
  • cref() 함수
    ref 함수에서 const 레퍼런스 인자를 위해 사용
profile
soeun choi

0개의 댓글