diff --git a/mfbt/Function.h b/mfbt/Function.h index 40b025602060..13d782f725a5 100644 --- a/mfbt/Function.h +++ b/mfbt/Function.h @@ -44,23 +44,80 @@ class FunctionImplBase { public: virtual ~FunctionImplBase() {} - virtual ReturnType call(Arguments... arguments) = 0; + virtual ReturnType call(Arguments... aArguments) = 0; }; +// Normal Callable Object. template class FunctionImpl : public FunctionImplBase +{ + public: + explicit FunctionImpl(const Callable& aCallable) + : mCallable(aCallable) {} + + ReturnType call(Arguments... aArguments) override + { + return mCallable(Forward(aArguments)...); + } + private: + Callable mCallable; +}; + +// Base class for passing pointer to member function. +template +class MemberFunctionImplBase : public FunctionImplBase { public: - explicit FunctionImpl(const Callable& aCallable) : mCallable(aCallable) {} + explicit MemberFunctionImplBase(const Callable& aCallable) + : mCallable(aCallable) {} ReturnType call(Arguments... aArguments) override { - return mCallable(Forward(aArguments)...); + return callInternal(Forward(aArguments)...); } private: + template + ReturnType callInternal(ThisType* aThis, Args&&... aArguments) + { + return (aThis->*mCallable)(Forward(aArguments)...); + } + + template + ReturnType callInternal(ThisType&& aThis, Args&&... aArguments) + { + return (aThis.*mCallable)(Forward(aArguments)...); + } Callable mCallable; }; +// For non-const member function specialization of FunctionImpl. +template +class FunctionImpl + : public MemberFunctionImplBase +{ +public: + explicit FunctionImpl(ReturnType(ThisType::*aMemberFunc)(Args...)) + : MemberFunctionImplBase(aMemberFunc) + {} +}; + +// For const member function specialization of FunctionImpl. +template +class FunctionImpl + : public MemberFunctionImplBase +{ +public: + explicit FunctionImpl(ReturnType(ThisType::*aConstMemberFunc)(Args...) const) + : MemberFunctionImplBase(aConstMemberFunc) + {} +}; + } // namespace detail // The primary template is never defined. As |Signature| is required to be diff --git a/mfbt/tests/TestFunction.cpp b/mfbt/tests/TestFunction.cpp index 3a531eb6d74a..6074fab950a6 100644 --- a/mfbt/tests/TestFunction.cpp +++ b/mfbt/tests/TestFunction.cpp @@ -23,7 +23,10 @@ struct ConvertibleToInt int increment(int arg) { return arg + 1; } struct S { + S() {} static int increment(int arg) { return arg + 1; } + int decrement(int arg) { return arg - 1;} + int sum(int arg1, int arg2) const { return arg1 + arg2;} }; struct Incrementor { @@ -82,6 +85,21 @@ TestReassignment() CHECK(f(42) == 44); } +static void +TestMemberFunction() +{ + Function f = &S::decrement; + S s; + CHECK((f(s, 1) == 0)); +} + +static void +TestConstMemberFunction() +{ + Function f = &S::sum; + const S s; + CHECK((f(&s, 1, 1) == 2)); +} int main() { @@ -91,5 +109,7 @@ main() TestLambda(); TestDefaultConstructionAndAssignmentLater(); TestReassignment(); + TestMemberFunction(); + TestConstMemberFunction(); return 0; }