std function

std::function과 std::bind를 이용하면 메소드 포인터를 간단하게 처리 할수 있다.
바로 구현으로 넘어간다.

std::function을 사용할려면 다음과 같이 functional 헤더를 포함 시킨다.

#include <functional>

1. 간단한 함수 포인터 예

#include <iostream>
#include <functional>

void Sub(int a, int b)
{
    printf("Sub : %d = %d - %d\n", a - b, a, b);
}

using  namespace  std::placeholders;
class Calculator
{
public:
    void Add(int a, int b) {
        printf("Add : %d = %d + %d\n", a+b, a, b);
    }

    void Func()
    {
        //std::function<void(int, int)> func = std::bind(&Calculator::Add, this, _1, _2);
        //auto를 사용하지 않으면 위와 같다.
        auto func = std::bind(&Calculator::Add, this, _1, _2);
        func(11, 4);
    }
};

int main(int argc, const char * argv[])
{
    //1) 함수 포인터와 placeholders 사용
    auto subFunc1 = std::bind(Sub, _1, _2);
    subFunc1(50, 10);

    //2) 함수 포인터와 placeholders 한개만 사용
    auto subFunc2 = std::bind(Sub, 100, std::placeholders::_1);
    subFunc2(10);

    //3) 메소드 함수 포인터로 이용
    auto calc = Calculator();
    calc.Func();
    return 0;
}

1), 2)번은 bind 함수를 통해 함수 포인터를 변수로 가진다.
    auto subFunc1 = std::bind(Sub, _1, _2);
    subFunc1(50, 10);


3) 클래스이름::메소드명, 객체의 포인터를 넘겨주면 메소드의 함수 포인터를 변수로 가진다.
    //std::function<void(int, int)> func = std::bind(&Calculator::Add, this, _1, _2);
    auto func = std::bind(&Calculator::Add, this, _1, _2);

2. std::ref 참조예

std::bind를 통해 객체를 넘길때는 참조로 넘겨야 복사가 안일어난다.

//std::ref 참조예
#include <iostream>
#include <functional>

using  namespace  std::placeholders;
class Calculator
{
public:
    void Add(int a, int b)
    {
        printf("Add : %d = %d + %d\n", a + b, a, b);
    }
};

int main(int argc, const char * argv[])
{
    Calculator calc;

    auto func1 = std::bind(&Calculator::Add, std::ref(calc), _1, 100);
    func1(200);

    int b = 10;
    auto func2 = std::bind(&Calculator::Add, std::ref(calc), _1, std::ref(b));
    func2(5);

}

calc 객체를 참조로 넘기고 있다.
auto func1 = std::bind(&Calculator::Add, std::ref(calc), _1, 100);

3. 예전의 콜백 방식

std::function 지원 안될때는 다음과 같이 부모의 순수 가상 함수를 통해 콜백을 많이 구현했다.

#include <iostream>

class ICalc {
public:
    virtual void Callback(int a, int b) = 0;
};

class Calculator : public ICalc
{
public:
    void Callback(int a, int b) {
        printf("Add : %d = %d + %d\n", a + b, a, b);
    }
};

void AddFunc(ICalc* calc)
{
    calc->Callback(22, 33);
}

int main(int argc, const char * argv[])
{
    Calculator calc;
    AddFunc(&calc);
    return 0;
}

4. std::function으로 간단하게 콜백 구현

#include <iostream>
#include <functional>

using  namespace  std::placeholders;
class Calculator
{
public:
    int Add(int a, int b)
    {
        printf("Calculator Add : %d = %d + %d\n", a + b, a, b);
        return (a + b);
    }
};

class Computer
{
public:
    int Add(int a, int b)
    {
        printf("Computer Add : %d = %d + %d\n", a + b, a, b);
        return (a + b);
    }
};

int AddFunc(std::function<int(int, int)> f)
{
    return f(100, 33);
}

int main(int argc, const char * argv[])
{
    Calculator calc;
    auto func1 = std::bind(&Calculator::Add, std::ref(calc), _1, _2);
    int a1 = AddFunc(func1);

    Computer comp;
    auto func2 = std::bind(&Computer::Add, std::ref(comp), _1, _2);
    int a2= AddFunc(func2);
    printf("Result :  %d , %d\n", a1, a2);

    //Lamda를 통해
    //[introducer capture] (parameters) -> return type { Code }
    AddFunc(
        [](int a, int b) -> int {
        printf("Lamda Add : %d = %d + %d\n", a + b, a, b);
        return (a + b);
    });
}

std::fuction 변수를  AddFunc  콜백 함수로 넘겨주고 있다.
    Calculator calc;
    auto func1 = std::bind(&Calculator::Add, std::ref(calc), _1, _2);
    int a1 = AddFunc(func1);

std::function 변수는 람다 함수를 넘겨도 된다.
    AddFunc(
        [](int a, int b) -> int {
        printf("Lamda Add : %d = %d + %d\n", a + b, a, b);
        return (a + b);
    });  }