Alon
Alon

Reputation: 1804

Correct function signature template for member function

Following up on a question I recently asked, there might be some unnecessary stuff in there but the example is small, what I want to do (and of course if you can think of other cool ways to do this, please share your thoughts), is to allow the user to activate a non virtual non interface correlating child method using a specific type (Please, let's concentrate on the how and not the why :) ).

My last error concerns the member function signature and not the selection actually, I can't figure how to allow perfect forwarding, I've tried current solution which can never work(copies), and I've also tried to transfer Args_t&& and forward, which did not work either, any suggestions on how to transfer the member function correctly? I suspect the activate function defenition is the wrong one...

I've added a code that demonstrates the compilation error, you can also change activate Args_t input parameter to Args_t&& and then forward(args)... to see the second...

Thanks.

struct Type {
    enum Value {
        One,
        Two
    };
};

struct A {};
template<typename Type_t, typename R, typename... Args_t>
auto activate(R (Type_t::* f)(Args_t...), A& parent, Args_t... args) -> R // args&& won't comppile either..
{ return (static_cast<Type_t&>(parent).*f)(args...); }

template<typename Type_t, typename R, typename... Args_t>
auto activate(R (Type_t::* f)(Args_t...) const, A const& parent, Args_t... args) -> R
{ return (static_cast<Type_t const&>(parent).*f)(args...); }

struct NonCopyable { public: NonCopyable() {} private: NonCopyable(NonCopyable const& other) {} };
struct B : public A { NonCopyable& foo(NonCopyable& other, bool test) { return other; } };
struct C : public A { NonCopyable& foo(NonCopyable& other, bool test) { return other; } }; // does something else obviously...

#define FuncSelect0(type, parent, func) \
        type == Type::One? activate<B>(&B::func, parent) :  \
            activate<C>(&C::func, parent)

#define FuncSelect1(type, parent, func, arg1) \
        type == Type::One? activate<B>(&B::func, parent, arg1) :  \
            activate<C>(&C::func, parent, arg1)

#define FuncSelect2(type, parent, func, arg1, arg2) \
        type == Type::One? activate<B>(&B::func, parent, arg1, arg2) :  \
            activate<C>(&C::func, parent, arg1, arg2)

#define GET_FS(_1,_2, _3, _4, _5, NAME,...) NAME
#define FuncSelect(...) (GET_FS(__VA_ARGS__, FuncSelect2, FuncSelect1, FuncSelect0)(__VA_ARGS__))

int main() {
        NonCopyable n;
        bool t;
        A* a = new B;
        NonCopyable& c = FuncSelect(Type::One, *a, foo, n, t);
        delete a;
        return 0;
}

Upvotes: 1

Views: 156

Answers (1)

Lingxi
Lingxi

Reputation: 14987

Not quite sure, but is this what you are looking for?

Updated: With these overloads in place, it should be really generic.

#include <iostream>
#include <utility>

struct X {};

struct A: X {
  int f(int a, int b) { return a + b; }
};

struct B: X {
  int f(int a, int b) const { return a * b; }
};

template <typename D, typename B>
const D& forward_cast(const B& b) { return (const D&)b; }
template <typename D, typename B> 
D& forward_cast(B& b) { return (D&)b; }
template <typename D, typename B>
const D&& forward_cast(const B&& b) { return (const D&&)b; }
template <typename D, typename B> 
D&& forward_cast(B&& b) { return (D&&)b; }

// I see no need to use the trailing return type syntax
template <typename T, typename TT, typename R, typename... Args, typename... Argss> inline
R activate(R (T::*pfn)(Args...), TT&& obj, Argss&&... args) {
  return (forward_cast<T>(std::forward<TT>(obj)).*pfn)(std::forward<Argss>(args)...);
}

template <typename T, typename TT, typename R, typename... Args, typename... Argss> inline
R activate(R (T::*pfn)(Args...) const, TT&& obj, Argss&&... args) {
  return (forward_cast<T>(std::forward<TT>(obj)).*pfn)(std::forward<Argss>(args)...);
}

int main() {
  A a;
  B b;
  X* p = &a;
  std::cout << activate(&A::f, *p, 1, 2) << '\n';
  p = &b;
  std::cout << activate(&B::f, *p, 1, 2) << '\n';
}

Upvotes: 1

Related Questions