Last active
January 16, 2021 13:32
-
-
Save paxbun/57e91071a3c95b97e3597b7e73d7d6ce to your computer and use it in GitHub Desktop.
std::function-like class with operator== implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <iostream> | |
| #include <typeindex> | |
| template <typename T> | |
| class Function; | |
| template <typename T, typename... Args> | |
| class Function<T(Args...)> | |
| { | |
| private: | |
| struct FunctionTraitBase | |
| { | |
| virtual T Call(void* pFunc, Args...) const = 0; | |
| virtual void* Copy(void* pFunc) const = 0; | |
| virtual bool Equals(void* pLhs, void* pRhs) const = 0; | |
| virtual void Delete(void* pFunc) const = 0; | |
| }; | |
| template <typename FuncT> | |
| struct FunctionTrait : public FunctionTraitBase | |
| { | |
| static FunctionTraitBase* GetInstance() | |
| { | |
| static FunctionTrait trait; | |
| return &trait; | |
| } | |
| virtual T Call(void* pFunc, Args... args) const override | |
| { | |
| FuncT& func = *reinterpret_cast<FuncT*>(pFunc); | |
| return func(std::forward<Args>(args)...); | |
| } | |
| virtual void* Copy(void* pFunc) const override | |
| { | |
| return new FuncT(*reinterpret_cast<FuncT*>(pFunc)); | |
| } | |
| virtual bool Equals(void* pLhs, void* pRhs) const override | |
| { | |
| FuncT &lhs = *reinterpret_cast<FuncT*>(pLhs), &rhs = *reinterpret_cast<FuncT*>(pRhs); | |
| return lhs == rhs; | |
| } | |
| virtual void Delete(void* pFunc) const override | |
| { | |
| delete reinterpret_cast<FuncT*>(pFunc); | |
| } | |
| }; | |
| private: | |
| FunctionTraitBase* _trait; | |
| std::type_index _idx; | |
| void* _pFunc; | |
| public: | |
| #ifdef __cpp_concepts | |
| template <typename FuncT> | |
| requires !std::is_same_v<Function, std::decay_t<FuncT>> | |
| #else | |
| template <typename FuncT, | |
| std::enable_if_t<!std::is_same_v<std::decay_t<FuncT>, Function>, int> = 0> | |
| #endif | |
| Function(FuncT&& func) : | |
| _trait { FunctionTrait<std::decay_t<FuncT>>::GetInstance() }, | |
| _idx { std::type_index { typeid(std::decay_t<FuncT>) } }, | |
| _pFunc { new std::decay_t<FuncT>(std::forward<FuncT>(func)) } | |
| {} | |
| Function(Function const& other) : | |
| _trait { other._trait }, | |
| _idx { other._idx }, | |
| _pFunc { other._trait->Copy(other._pFunc) } | |
| {} | |
| Function(Function&& other) : | |
| _trait { other._trait }, | |
| _idx { other._idx }, | |
| _pFunc { other._pFunc } | |
| { | |
| other._pFunc = nullptr; | |
| } | |
| Function& operator=(Function const& other) | |
| { | |
| if (this != &other) | |
| { | |
| _trait->Delete(_pFunc); | |
| _trait = other._trait; | |
| _idx = other._idx; | |
| _pFunc = other._trait->Copy(other._pFunc); | |
| } | |
| return *this; | |
| } | |
| Function&& operator=(Function&& other) | |
| { | |
| if (this != &other) | |
| { | |
| _trait->Delete(_pFunc); | |
| _trait = other._trait; | |
| _idx = other._idx; | |
| _pFunc = other._pFunc; | |
| other._pFunc = nullptr; | |
| } | |
| return *this; | |
| } | |
| ~Function() | |
| { | |
| _trait->Delete(_pFunc); | |
| } | |
| public: | |
| T operator()(Args... args) const | |
| { | |
| return _trait->Call(_pFunc, std::forward<Args>(args)...); | |
| } | |
| bool operator==(Function const& other) const | |
| { | |
| return _idx == other._idx && _trait->Equals(_pFunc, other._pFunc); | |
| } | |
| }; | |
| struct Adder | |
| { | |
| int i; | |
| bool operator==(Adder const& other) | |
| { | |
| return i == other.i; | |
| } | |
| int operator()(int j) | |
| { | |
| return i + j; | |
| } | |
| }; | |
| int foo(int i) | |
| { | |
| return i + 15; | |
| } | |
| float baz(float& a, float b) | |
| { | |
| a *= 2; | |
| return a + b; | |
| } | |
| void var() | |
| { | |
| std::cout << "Hello, world!" << std::endl; | |
| } | |
| int main() | |
| { | |
| Adder adder1 { 15 }, adder2 { 21 }, adder3 { 15 }; | |
| Function<int(int)> func1 = adder1, func2 = adder2, func3 = adder3, func4 = foo, | |
| func5 = [](int i) { return i + 15; }, func6 = foo; | |
| Function<float(float&, float)> ffunc = baz; | |
| Function<void()> vfunc = var; | |
| var(); | |
| std::cout << std::boolalpha; | |
| std::cout << "func1(20) = " << func1(20) << std::endl; | |
| std::cout << "func2(20) = " << func2(20) << std::endl; | |
| std::cout << "func3(20) = " << func3(20) << std::endl; | |
| std::cout << "func4(20) = " << func4(20) << std::endl; | |
| std::cout << "func5(20) = " << func5(20) << std::endl; | |
| std::cout << "func6(20) = " << func6(20) << std::endl; | |
| Function<int(int)> func7 = func2; | |
| std::cout << "func7(20) = " << func7(20) << std::endl; | |
| std::cout << "(func1 == func2) = " << (func1 == func2) << std::endl; | |
| std::cout << "(func1 == func3) = " << (func1 == func3) << std::endl; | |
| std::cout << "(func1 == func4) = " << (func1 == func4) << std::endl; | |
| std::cout << "(func1 == func5) = " << (func1 == func5) << std::endl; | |
| std::cout << "(func4 == func6) = " << (func4 == func6) << std::endl; | |
| std::cout << "(func2 == func7) = " << (func2 == func7) << std::endl; | |
| float a = 25.0f; | |
| std::cout << "a = " << a << std::endl; | |
| std::cout << "ffunc(a, 24.0f) = " << ffunc(a, 24.0f) << std::endl; | |
| std::cout << "a = " << a << std::endl; | |
| return foo(15); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment