bind
우선 bind부터 알아야 한다.
#include <iostream>
#include <functional>
using namespace std;
using namespace std::placeholders;
void f1(int a, int b, int c) { printf("f1 : %d, %d, %d\n", a,b,c); }
void f2(int& a) { a = 20; }
int main()
{
bind(&f1, 1, 2, 3)(); // f1(1,2,3)으로 고정된다.
bind(&f1, 1, 2, _1)(10); // f1(1,2,10)으로 고정된다.
bind(&f1, 1, _2, _1)(10, 20); // f1(1,20,10)으로 고정된다.
}
void f2(int& a) { a = 20; }
int n = 0;
bind(&f2, n)(); // f2(n)
cout << n << endl; // 20? or 0? -> 0이 나온다.
reference_wrapper<int> r(n); // 20이 나온다.
bind(&f2, ref(n))(); // reference_wrapper를 매번치기 힘드니.
#include <iostream>
#include <functional>
using namespace std;
using namespace std::placeholders;
class Test
{
public:
int data = 0;
void f(int a, int b) // == void f(Test* this, int a, int b)
{
data = a;
printf("f : %d, %d\n", a, b);
}
};
int main()
{
Test t;
bind(&Test::f, &t, 1, 2)(); // t.f(1,2)
// bind(&Test::f, ref(t), 1, 2)(); // 동일표현
bind(&Test:data, &t)() = 10; // t.data = 10
cout << t.data << endl;
}
- 쓰는 법은 이제 알겠다. 그런데 이걸 어디쓰지???
- 언제쓰는지는 가장아래 Example을 참조하자.
Function
#include <iostream>
#include <functional>
using namespace std;
using namespace std::placeholders;
void f1(int a) { printf("f1 : %d\n", a); }
void f2(int a, int b, int c) { printf("f2 : %d, %d, %d\n", a, b, c); }
int main()
{
void(*f)(int) = &f1; // ok
void(*f)(int) = &f2; // error
// 함수 포인터는 signature가 동일해야한다
function<void(int)> f; // 리턴이 void이고 입력이 int면 다된다.
f = &f1; // ok
f = bind(&f2, 1,2,_1) // ok
f(10); // f2(1,2,10);
bind(&f2, 1,2,_1)(10); // 는 그냥 호출임을 기억
}
#include <iostream>
#include <functional>
using namespace std;
using namespace std::placeholders;
class Test
{
public:
int data = 0;
void f(int a, int b)
{
data = a;
printf("f : %d, %d\n", a, b);
}
};
int main()
{
Test t;
function<void(int)> f1;
f1 = bind(&Test::f, &t, _1, 20);
// 일반 함수 모양의 function
f1(10); // t.f1(10, 20);
// 객체를 function의 인자로 받는 방법
function<void(Test*, int)> f2;
f2 = bind(&Test::f, _1, _2, 20);
f2(&t, 100); // t.f(100, 20)
function<void(Test, int)> f3;
f3 = bind(&Test::f, _1, _2, 20);
f3(&t, 200); // t.f(200, 20)
function<void(Test&, int)> f4;
f4 = bind(&Test::f, _1, _2, 20);
f4(&t, 300); // t.f(200, 20)
cout << t.data << endl;
}
#include <iostream>
#include <functional>
using namespace std;
using namespace std::placeholders;
class Test
{
public:
int data = 10;
};
int main()
{
Test t1, t2;
function<int()> f1;
f1 = bind(&Test::data, &t1); // t1.data
cout << f1() << endl; // t1.data get
f1() = 20; // error - functiond이 값으로 리턴하기에
function<int&()> f2;
f2() = 20; // ok
function<int&(Test*)> f2;
f2 = bind(&Test::data, _1);
f2(t1) = 20; // ok
f2(t2) = 40; // ok
}
Example
#include <iostream>
#include <string>
#include <functional>
#include <map>
#include <vector>
using namespace std;
using namespace std::placeholders;
class NotificationCenter
{
using HANDLER = function<void(void*)>;
map<string, vector<HANDLER>> notif_map;
public:
void Register(string key, HANDLER h)
{
notif_map[key].push_back(h);
}
void Notify(string key, void* param)
{
vector<HANDLER>& v = notif_map[key];
for(auto f : v)
f(param);
}
};
void f1(void* p) { cout << "f1" << endl;}
void f2(void* p, int a, int b) { cout << "f2" << endl;}
int main()
{
NotificationCenter nc;
nc.Register("CONNECT_WIFI", &f1);
nc.Register("CONNECT_WIFI", bind(&f2, _1, 0, 0));
nc.Notify("CONNECT_WIFI", (void*)0);
}
Examle-2
// Packet수신시 Packet에 따라 무한히 많은 If-else문 혹은 Switch-Case문 보다
// 배열로 Function을 선언해 두고 Packet Id에 따라 호출되게 만들 수 있다
#pragma once
#include "Protocol.pb.h"
using PacketHandlerFunc = std::function<bool(PacketSessionRef&, BYTE*, int32)>;
extern PacketHandlerFunc GPacketHandler[UINT16_MAX];
// TODO : 자동화
enum : uint16
{
PKT_S_TEST = 1,
PKT_S_LOGIN = 2,
};
// TODO : 자동화
// Custom Handlers
bool Handle_INVALID(PacketSessionRef& session, BYTE* buffer, int32 len);
bool Handle_S_TEST(PacketSessionRef& session, Protocol::S_TEST& pkt);
class ClientPacketHandler
{
public:
// TODO : 자동화
static void Init()
{
for (int32 i = 0; i < UINT16_MAX; i++)
GPacketHandler[i] = Handle_INVALID;
GPacketHandler[PKT_S_TEST] = [](PacketSessionRef& session, BYTE* buffer, int32 len) { return HandlePacket<Protocol::S_TEST>(Handle_S_TEST, session, buffer, len); };
}
static bool HandlePacket(PacketSessionRef& session, BYTE* buffer, int32 len)
{
PacketHeader* header = reinterpret_cast<PacketHeader*>(buffer);
return GPacketHandler[header->id](session, buffer, len);
}
private:
template<typename PacketType, typename ProcessFunc>
static bool HandlePacket(ProcessFunc func, PacketSessionRef& session, BYTE* buffer, int32 len)
{
PacketType pkt;
if (pkt.ParseFromArray(buffer + sizeof(PacketHeader), len - sizeof(PacketHeader)) == false)
return false;
return func(session, pkt);
}
};