취미생활
[C++] Map 과 함수 포인터를 이용한 함수 호출 아이디어 본문
중국에 출장을 와서 마라탕도 먹어보고.. 근로기준법에 적혀있는 근무시간도 어겨가면서 일을 하면서 프로그래밍도 해보고있는데, 별 생각없이 코드를 보다가 그런 생각이 들었다.
아래 코드는 회사에서 사용하고 있는 코드는 아니고, 예시로 내가 적은 코드인데
#include <iostream>
#include <string.h>
using namespace std;
void A() { cout << "hello world!" << endl; }
void B() { cout << "world hello!" << endl; }
int main()
{
const char *name = "A";
if(strcmp(name, "A") == 0)
{
A();
}
else if(strcmp(name, "B") == 0)
{
B();
}
}
요약하자면 함수 이름과 매칭되는 함수를 실행하는 함수인데, 이 코드를 보면서 너무 비효율적이지 않을까라는 생각이 들었다. 앞으로도 코드는 계속 수정될 것이고, 그럴 때 마다 저기 if 문에서 계속 무언가를 추가해줘야 한다니.. 너무 끔찍하기 짝이 없다.
r그래서 알아보던 도중에 C++ 에서 지원하는 STL 중 Map Container 가 눈에 들어왔다.
Map Container 는 쉽게 설명하자면 Key, Value로 이루어진 Tree 인데 Key 값으로 Int, Char, String 등등.. 유저가 원하는 값을 입력할 수 있고 대괄호를 통해 Array 호출하듯이 사용할 수 있다. (Python의 Dictionary 와 비슷하다) 그럼 이름이 같은 경우가 생기지 않을까? 라는 의문이 들 수도 있는데, Map Container는 중복되는 Key 값을 허용하지 않으므로 그럴 일은 없다. Value 값은 중복이 되도 상관 없기에 해당 사항이 없었다.
그렇다면 어떻게 map Container 와 함수를 연결할 수 있을까?
일단 map Conatiner의 구조는 Key / Value 구조로 되어있으니 Key 값에는 함수의 이름, Value 값에는 함수를 호출할 수 있는 함수 포인터를 가지는 방식으로 구성하면 된다.
#include <map>
typedef void (*FuncP)(void);
int main()
{
map<string, FuncP> a;
map<string, void (*)(void)> b;
}
구조를 보면 이런 식이다.
a 의 경우에는 typedef를 통해 함수 포인터 타입을 선언해 map의 value 값으로 사용하는 방식이고, b 의 경우에는 typedef 없이 함수 포인터를 직접 넣어서 map을 선언하는 방식이다. 처음에는 typedef 로 함수 포인터를 선언해야만 사용할 수 있을 줄 알았는데, 나중에 확인해보니까 b 형태도 가능하더라.
여튼 이런식으로 선언을 한 뒤에 함수 호출을 하는 것까지 코드 전문을 확인하면 아래와 같다.
#include <iostream>
#include <string.h>
#include <map>
using namespace std;
void A() { cout << "hello world!" << endl; }
void B() { cout << "world hello!" << endl; }
typedef void (*FuncP)(void);
int main()
{
map<string, void (*)(void)> a;
a["A"] = A;
a["B"] = B;
a["A"]();
a["B"]();
return 1;
}
hello world!
world hello!
실행하면 다음과 같이 나오는데, 이건 어디까지나 단위테스트 용으로 만든 것이라서 호출 할 때 하드코딩 방식으로 진행을 했다. 업무에 실제로 적용한다면 아마 다음과 같은 모양이 될 듯 하다.
#include <iostream>
#include <string.h>
#include <map>
using namespace std;
void A() { cout << "hello world!" << endl; }
void B() { cout << "world hello!" << endl; }
typedef void (*FuncP)(void);
int main()
{
string Name = "A";
map<string, void (*)(void)> a;
a["A"] = A;
a["B"] = B;
if(a.find(Name) != a.end())
{
a[Name]();
}
else
{
cout << "Name is Not Matching : " << Name << endl;
}
return 1;
}
map Container의 Key 값을 찾는 find 함수를 통해 map 에서 일치하는 key 값을 찾은 뒤 Value에 들어있는 함수 포인터를 실행하는 방식이다. 아마 업무에 실제로 적용되면 이런 식으로 적용될 것 같은데, 이런 방식으로 코딩하면 더이상 if-else 혹은 switch 문으로 호출 코드를 넣어주지 않아도 되어서 편리하지만, map Container 를 세팅해줘야 한다는 단점이 생겼다.
결론은 if-else 를 쓰든지 map Container 를 통해 사용하든지 코드가 길어지는 건 막을 수 없다. 오히려 map Container 를 통해 호출하면 값을 세팅해주는 시간이 추가되기 때문에 시간이 좀 더 걸릴 듯 하다.
결론은 실제 업무에서 사용하기 부적합함.
2022-11-16 Modern C++ 코드 업데이트
#include <iostream>
#include <string>
#include <map>
#include <functional>
using namespace std;
void A() { cout << "hello world!" << endl; }
void B() { cout << "world hello!" << endl; }
int main()
{
string Name = "A";
map<string, function<void()>> a = {{"A", A}, {"B", B}};
if(a.find(Name) != a.end())
{
a[Name]();
}
else
{
cout << "Name is Not Matching : " << Name << endl;
}
return 0;
}
C++ 99 -> C++ 11 업데이트
'컴퓨터 > C++' 카테고리의 다른 글
[C++11 Qt] QTableView 로 틀 고정 기능 구현하기 (0) | 2023.04.03 |
---|---|
[C++] 람다 함수로 std::thread 돌리기 (0) | 2023.03.29 |
[C++11] std::function 템플릿으로 함수 포인터 대체하기 (0) | 2022.11.16 |
[C++11] 중괄호로 STL 자료구조 초기화 간편하게 하기 (0) | 2022.11.16 |
[C++] 구조체 비트 필드로 비트 단위 변수 사용하기 (0) | 2022.09.05 |