아이디어

한창 코딩을 하다 문득 멤버 함수를 특정 객체에서나 캐스팅 없이 호출할수 있으면 어떨까 하는 생각이 떠올랐습니다. 해당 클래스의 타입을 몰라도 되고, "함수명"으로 호출하고, 인자도 넘겨 줄수 있는 방법이 있다면, 뭔가 편리할 것 같다는 쓸데 없는 생각이 들었습니다.

목표

  • 클래스 멤버 함수를 "다른 곳"에서 "이름"으로 함수를 호출 할 수 있다.
  • 원하는 인자를 넘겨 줄 수 있다.

구현

#include <iostream>
#include <functional>
#include <any>
#include <unordered_map>

class Dispatcher
{
public:
    void Register(std::string_view name, std::any func)
    {
        mDispatcherList.insert(std::make_pair(name, func));
    }

    template<typename T1>
    void Invoke(std::string_view name, T1 param1)
    {
        std::any_cast<std::function<void(T1)>>(mDispatcherList[name.data()])(param1);
    }

    template<typename T1, typename T2>
    void Invoke(std::string_view name, T1 param1, T2 param2)
    {
        std::any_cast<std::function<void(T1, T2)>>(mDispatcherList[name.data()])(param1, param2);
    }

private:
    std::unordered_map<std::string, std::any> mDispatcherList;
};

Dispatcher sDispatcher;

#define DECLARE_FUNC_ARG1(classname, func, arg1) \
    std::function<void(arg1)> Dispatcher_##classname##_##func;
#define DECLARE_FUNC_ARG2(classname, func, arg1, arg2) \
    std::function<void(arg1, arg2)> Dispatcher_##classname##_##func;

#define REGIST_FUNC_ARG1(classname, func) \
    Dispatcher_##classname##_##func = std::bind(&classname::func, this, std::placeholders::_1); \
    sDispatcher.Register(#func, Dispatcher_##classname##_##func);
#define REGIST_FUNC_ARG2(classname, func) \
    Dispatcher_##classname##_##func = std::bind(&classname::func, this, std::placeholders::_1, std::placeholders::_2); \
    sDispatcher.Register(#func, Dispatcher_##classname##_##func);

class Foo
{
public:
    Foo()
    {
        REGIST_FUNC_ARG1(Foo, PrintArg1);
        REGIST_FUNC_ARG2(Foo, PrintArg2);
    }

public:
    void PrintArg1(int t1)
    {
        std::cout << "Hello World!\n";
        std::cout << t1 << std::endl;
    }

    void PrintArg2(int t1, float t2)
    {
        std::cout << "Hello World!\n";
        std::cout << t1 << std::endl;
        std::cout << t2 << std::endl;
    }

private:
    DECLARE_FUNC_ARG1(Foo, PrintArg1, int);
    DECLARE_FUNC_ARG2(Foo, PrintArg2, int, float);
};

int main()
{
    Foo *foo = new Foo;

    sDispatcher.Invoke("PrintArg1", 5);
    sDispatcher.Invoke("PrintArg2", 1, 0.5f);
}

+ Recent posts