Replace macro with function / template

I would like to replace the macro with the / template function:

#define FOO( f ) \
    int result = m_Member.f; \
    switch ( result ) \
    { \
    case 1: \
        m_pMember1->f; \
        break;
    case 2:
        m_pMember2->f; \
        break;
    }

class foo
{
public:
    void foo1(int x, int y)
    {
        FOO( foo1(x, y) )
    }
    void foo2(int x, double y, void *z)
    {
        FOO( foo2(x, y) )
    }
protected:
    fooA m_Member;
    fooB m_Member1;
    fooC m_Member2;
};

So my problem is that the function name is passed to the macro along with the arguments. I can rewrite the call to something like FOO (foo1, x, y) and then process the list of variables. Thus, a macro will define only one function call. But maybe there is a more elegant solution.

+3
source share
3 answers

As is, it is impossible.

The problem is that the template is intrinsically safe in type. However, your example is not. There is nothing inherent in the name foo2that holds back the set of types on which it can be applied!

To illustrate this problem, consider a typical member function:

struct Foo { int doit(double x, double y); };

int (Foo::*)(double,double).

, , , .

, doit ... , :

class foo {
public:
    void foo1(int x, int y)
    {
        dispatch(&fooA::foo1, &fooB::foo1, &fooC::foo1, x, y);
    }

    void foo2(int x, double y, void *z)
    {
        dispatch(&fooA::foo2, &fooB::foo2, &fooC::foo2, x, y, z);
    }

private:
    template <typename... Args>
    void dispatch(int (fooA::* f)(Args...),
                  void (fooB::* g)(Args...),
                  void (fooC::*h)(Args...),
                  Args... args)
    {
        switch((m_Member.*f)(args...)) {
        case 1: (m_Member1.*g)(args...); return;
        case 2: (m_Member2.*h)(args...); return;
        }
    }

    fooA m_Member;
    fooB m_Member1;
    fooC m_Member2;
};

, .

+2

fooB fooC ( foo_base ) , :

class foo
{
private:
    template<typename... Ts>
    void another_foo(int (fooA::*f)(Ts...), void (foo_base::*g)(Ts...), Ts const... vals)
    {
        switch ((m_Member.*f)(vals...)) {
        case 1:
            (m_pMember1->*g)(vals...);
            break;

        case 2:
            (m_pMember2->*g)(vals...);
            break;
        }
    }

public:
    void foo1(int x, int y)
    {
        another_foo(&fooA::foo1, &foo_base::foo1, x, y);
    }

    void foo2(int x, double y, void *z)
    {
        another_foo(&fooA::foo2, &foo_base::foo2, x, y);
    }

protected:
    fooA m_Member;
    fooB m_Member1;
    fooC m_Member2;
};

, , , m_pMember1 m_pMember2 .

0

The following may help: ( http://ideone.com/5QIBZx )

#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;
};
0
source

All Articles