
#include <iostream>

struct fooA {
    int foo1(int x, int y) { return x + y; }
    int foo2(int x, double y, void *) { return x + y; }
};
struct fooB {
    void foo1(int x, int y) { std::cout << "fooB(" << x << ", " << y << ")\n"; }
    void foo2(int x, double y, void *z) { std::cout << "fooB(" << x << ", " << y << ", " << z << ")\n"; }
};
struct fooC {
    void foo1(int x, int y) { std::cout << "fooC(" << x << ", " << y << ")\n"; }
    void foo2(int x, double y, void *z) { std::cout << "fooC(" << x << ", " << y << ", " << z << ")\n"; }
};

#define Return(ret) decltype ret { return ret; }

struct foo1Caller
{
    template <typename T, typename... Args>
    auto operator () (T& t, Args... args) -> Return((t.foo1(args...)))
};

struct foo2Caller
{
    template <typename T, typename... Args>
    auto operator () (T& t, Args... args) -> Return((t.foo2(args...)))
};


class foo
{
public:
    void foo1(int x, int y)
    {
        dispatch(foo1Caller(), x, y);
    }
    void foo2(int x, double y, void *z)
    {
        dispatch(foo2Caller(), x, y, z);
    }

private:
    template <typename T, typename... Args>
    void dispatch(T caller, Args... args)
    {
        switch (caller(m_Member, args...)) {
            case 1: caller(m_Member1, args...); return;
            case 2: caller(m_Member2, args...); return;
        }
    }

    fooA m_Member;
    fooB m_Member1;
    fooC m_Member2;
};

int main()
{
    foo dispatcher;
    dispatcher.foo1(1, 0);
    dispatcher.foo2(1, 1, 0);
    return 0;
}
