As the following example v0::test()
, we want to write a template function to invoke all class C
's member funtions using class C
's member function pointer as template arguement, but this way failed on inherited member functions from parients. To ease those failures, we have to add an overload for every base class(see v1::test()
), and in some more complicated case its even difficult to write the base class name such as std:tuple
, or change the whole function design to v2...v4
.
Is there any better way?
struct A {
void fa() {}
};
struct B : A {
void fb() {}
};
struct C : B {
void fc() {}
};
namespace v0 {
using c_mem_fn = void (C::*)();
template <c_mem_fn fn>
void invoke_c_mem_fn(C* c) {
(c->*fn)();
}
void test() {
C cc;
C* c = &cc;
invoke_c_mem_fn<&C::fc>(c);
// invoke_c_mem_fn<&B::fb>(c); // compile error
// invoke_c_mem_fn<&A::fa>(c); // compile error
// invoke_c_mem_fn<&C::fb>(c); // compile error
// invoke_c_mem_fn<&C::fa>(c); // compile error
}
} // namespace v0
namespace v1 {
using c_mem_fn = void (C::*)();
template <c_mem_fn fn>
void invoke_c_mem_fn(C* c) {
(c->*fn)();
}
using b_mem_fn = void (B::*)();
template <b_mem_fn fn>
void invoke_c_mem_fn(C* c) {
(c->*fn)();
}
template <void (A::*fn)()>
void invoke_c_mem_fn(C* c) {
(c->*fn)();
}
void test() {
C cc;
C* c = &cc;
invoke_c_mem_fn<&C::fc>(c);
invoke_c_mem_fn<&B::fb>(c);
invoke_c_mem_fn<&A::fa>(c);
invoke_c_mem_fn<&C::fb>(c);
invoke_c_mem_fn<&C::fa>(c);
}
} // namespace v1
namespace v2 {
template <typename Fn, Fn fn>
void invoke_c_mem_fn(C* c) {
(c->*fn)();
}
void test() {
C cc;
C* c = &cc;
invoke_c_mem_fn<decltype(&C::fc), &C::fc>(c);
invoke_c_mem_fn<decltype(&B::fb), &B::fb>(c);
invoke_c_mem_fn<decltype(&A::fa), &A::fa>(c);
invoke_c_mem_fn<decltype(&C::fb), &C::fb>(c);
invoke_c_mem_fn<decltype(&C::fa), &C::fa>(c);
}
} // namespace v2
namespace v3 {
template <typename Fn>
void invoke_c_mem_fn(Fn fn, C* c) {
(c->*fn)();
}
void test() {
C cc;
C* c = &cc;
invoke_c_mem_fn(&C::fc, c);
invoke_c_mem_fn(&B::fb, c);
invoke_c_mem_fn(&A::fa, c);
invoke_c_mem_fn(&C::fb, c);
invoke_c_mem_fn(&C::fa, c);
}
} // namespace v3
namespace v4 {
template <typename X, void (X::*fn)()>
void invoke_c_mem_fn(C* c) {
(c->*fn)();
}
void test() {
C cc;
C* c = &cc;
invoke_c_mem_fn<C, &C::fc>(c);
invoke_c_mem_fn<B, &B::fb>(c);
invoke_c_mem_fn<A, &A::fa>(c);
// invoke_c_mem_fn<C, &C::fb>(c); // compiler error
// invoke_c_mem_fn<C, &C::fa>(c); // compiler error
invoke_c_mem_fn<B, &C::fb>(c);
invoke_c_mem_fn<A, &C::fa>(c);
}
} // namespace v4
int main() {
v1::test();
v2::test();
v3::test();
v4::test();
}
I finally found the c++17 syntax template <auto>
in v5::test()
, this solved my problem, thanks you all for reading and answering.
namespace v5 {
template <auto fn>
void invoke_c_mem_fn(C* c) {
(c->*fn)();
}
void test() {
C cc;
C* c = &cc;
invoke_c_mem_fn<&C::fc>(c);
invoke_c_mem_fn<&B::fb>(c);
invoke_c_mem_fn<&A::fa>(c);
invoke_c_mem_fn<&C::fb>(c);
invoke_c_mem_fn<&C::fa>(c);
}
} // namespace v5