취미생활

[C++] Map 과 함수 포인터를 이용한 함수 호출 아이디어 본문

컴퓨터/C++

[C++] Map 과 함수 포인터를 이용한 함수 호출 아이디어

달다달아 2022. 11. 16. 12:38

중국에 출장을 와서 마라탕도 먹어보고.. 근로기준법에 적혀있는 근무시간도 어겨가면서 일을 하면서 프로그래밍도 해보고있는데, 별 생각없이 코드를 보다가 그런 생각이 들었다.

 

아래 코드는 회사에서 사용하고 있는 코드는 아니고, 예시로 내가 적은 코드인데

#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 업데이트

Comments