leesangwon0114

I am Research Engineer. Currently working in KT.

C++Intermediate 27. reference wrapper

27 Nov 2018 » c++

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 는 보관할 수 있음
}