codenuri 강석민 강사 강의 내용기반으로 정리한 내용입니다.
std::bind & std::ref
#include <iostream>
#include <functional>
using namespace std;
void foo() {}
void goo(int a) {}
int main()
{
    void(*f)() = &foo;
    // f = &goo; // error
    function<void()> f2 = &foo;
    f2(); // foo()
    f2 = bind(&goo, 5);
    f2(); // goo(5);
}
핵심 정리
1. std::function
- 함수 포인터 역할을 하는 템플릿
 - 일반 함수 뿐 아니라 함수 객체, 람다 표현식 등도 담을 수 있다.
 - bind 와 함께 사용하면 인자의 개수가 다른 함수(함수 객체)도 사용할 수 있다.
 
2. std::bind
- 함수 또는 함수 객체의 인자를 고정할 때 사용한다.
 - 인자의 값을 고정 할 때 값 방식을 사용한다.
 - 참조로 인자를 고정하려면 ref() 또는 cref()를 사용한다.
 
#include <iostream>
#include <functional>
using namespace std;
void goo(int& a) { a = 30; }
int main()
{
    int n = 0;
    function<void()> f;
    f = bind(&goo, n); // 값으로 고정
    f(); // goo(n);
    cout << n << endl; // 0
}
출력이 0이 나옴
``` cpp
#include <iostream>
#include <functional>
using namespace std;
void goo(int& a) { a = 30; }
int main()
{
    int n = 0;
    function<void()> f;
    f = bind(&goo, ref(n)); // 참조로 고정
    f(); // goo(n);
    cout << n << endl; // 30
}
아예 n을 보낼 때 참조를 보내면 되는데 왜 값으로 보냈을까?
#include <iostream>
#include <functional>
using namespace std;
void goo(int& a) { a = 30; }
int main()
{
    function<void()> f;
    // 다른 구간이라 보면
    {
        int n = 0;
        f = bind(&goo, n);
    }
    // n 을 참조로 보내면 블럭 벗어나면 파괴되버림...
    f(); // goo(n);
    cout << n << endl; // 30
}
std::reference_wrapper
#include <iostream>
using namespace std;
void foo(int& a) { a = 30; }
template<typename F, typename T>
void chronometry(F f, T& arg)
{
    f(arg);
}
int main()
{
    int n = 0;
    chronometry(&foo, n);
    function<void()> f;
    f = bind(&foo, n);
    // 아래 호출 해야 n이 전달됨(n 이 전달되기 전에 파괴될 가능성이 있음)
    
    f();
}
ref 로 보내야함
chronometry 의 인자를 값으로 받으면서 해결해보기
#include <iostream>
using namespace std;
void foo(int& a) { a = 30; }
template<typename F, typename T>
void chronometry(F f, T arg)
{
    f(arg);
}
int main()
{
    int n = 0;
    chronometry(&foo, &n);
}
핵심 1. 주소를 전달한다.
핵심 2. 포인터가 참조로 암시적 형변환 되면 가능하다.
참조로 변환 가능한 포인터
#include <iostream>
using namespace std;
template<typename T> struct xreference_wrapper
{
    T* ptr;
public:
    xreference_wrapper(T& r) : ptr(&r) {}
    operator T&() { return *ptr; }
};
int main()
{
    int n = 0;
    xreference_wrapper<int> ref(n); // 결국 주소보관
    int& r = ref; // ref.operator int&()
    r = 30;
    cout << n << endl; // 30
}
reference_wrapper
- 참조와 유사하게 동작하는 클래스 템플릿
 - 참조로 변환 가능한 포인터
 
ref, cref
- reference_wrapper를 생성하는 helper 함수
 
chronometry 와 결합
#include <iostream>
using namespace std;
template<typename T> struct xreference_wrapper
{
    T* ptr;
public:
    xreference_wrapper(T& r) : ptr(&r) {}
    operator T&() { return *ptr; }
};
void foo(int& a) { a = 30; }
template<typename F, typename T>
void chronometry(F f, T arg)
{
    f(arg);
}
tempalte<typename T>
xreference_wrapper<T> xref(T& obj)
{
    return xreference_wrapper<T>(obj);
}
int main()
{
    int n = 0;
    // xreference_wrapper<int> r(n); // n 주소
    // chronometry(&foo, r);
    // chronometry(&foo, xreference_wrapper<int>(n));
    chronometry(&foo, xref(n));
    cout << n << endl; // 30
}
#include <iostream>
#include <functional>
using namespace std;
int main()
{
    int n1 = 10;
    int n2 = 20;
    // int& r1 = n1;
    // int& r2 = n2;
    reference_wratpper<int> r1(n1);
    reference_wratpper<int> r2(n2);
    r1 = r2;
    cout << n1 << endl; // 10
    cout << n2 << endl; // 20
    cout << r1 << endl; // 20
    cout << r2 << endl; // 20
    // vetor<int&> v(10); // reference_wrapper 는 보관할 수 있음
}