Skip to content

Instantly share code, notes, and snippets.

@paxbun
Last active January 16, 2021 13:32
Show Gist options
  • Select an option

  • Save paxbun/57e91071a3c95b97e3597b7e73d7d6ce to your computer and use it in GitHub Desktop.

Select an option

Save paxbun/57e91071a3c95b97e3597b7e73d7d6ce to your computer and use it in GitHub Desktop.
std::function-like class with operator== implementation
#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