Reputation: 53
I would like to replace a macro with a function / template:
#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 function name is passed to a macro together with arguments. I can rewrite call to something like FOO( foo1, x, y ) and then deal with variable argument list. So macro will define just a single function call. But maybe there's a more elegant solution.
Upvotes: 5
Views: 3027
Reputation: 217850
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;
};
Upvotes: 0
Reputation: 300049
As is, this is not possible.
The problem is that a template is, by nature, type-safe. Your example, however, is not. There is nothing inherent to the name foo2
that constrains the set of types on which it may be applied!
To illustrate the issue, consider a typical member function:
struct Foo { int doit(double x, double y); };
Its type is int (Foo::*)(double,double)
.
Note how the name of the class the method belongs to appear in the type itself.
Thus, you cannot invoke doit
on two unrelated classes... so I am afraid that you'll get some repetition:
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;
};
And yes, it works.
Upvotes: 3
Reputation: 14400
If you can add a base class to fooB
and fooC
(called foo_base
here) with some virtual functions then you can do this with the following code:
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;
};
The virtual functions will likely get devirtualised because the static type of m_pMember1
and m_pMember2
is statically known.
Upvotes: 0