function.hpp 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. #pragma once
  2. #include <utility>
  3. #include <type_traits>
  4. namespace std {
  5. namespace __inner {
  6. template <typename Ret, typename... Args>
  7. class _function_base {
  8. public:
  9. constexpr _function_base() = default;
  10. virtual constexpr ~_function_base() = default;
  11. virtual constexpr Ret operator()(Args&&... args) const = 0;
  12. };
  13. template <typename FuncLike, typename Ret, typename... Args>
  14. class _function : public _function_base<Ret, Args...> {
  15. private:
  16. FuncLike func;
  17. public:
  18. constexpr _function(FuncLike&& _func)
  19. : func(std::forward<FuncLike>(_func))
  20. {
  21. }
  22. constexpr ~_function() = default;
  23. constexpr Ret operator()(Args&&... args) const override
  24. {
  25. return func(std::forward<Args>(args)...);
  26. }
  27. };
  28. } // namespace __inner
  29. template <typename>
  30. class function;
  31. template <typename Ret, typename... Args>
  32. class function<Ret(Args...)> {
  33. private:
  34. char _data[sizeof(void*) * 2];
  35. using fb_t = __inner::_function_base<Ret, Args...>;
  36. constexpr fb_t* _f(void) const
  37. {
  38. return (fb_t*)_data;
  39. }
  40. public:
  41. template <typename FuncLike>
  42. constexpr function(FuncLike&& func)
  43. {
  44. static_assert(sizeof(FuncLike) <= sizeof(_data));
  45. new (_f()) __inner::_function<FuncLike, Ret, Args...>(std::forward<FuncLike>(func));
  46. }
  47. template <typename FuncPtr>
  48. constexpr function(FuncPtr* funcPtr)
  49. {
  50. new (_f()) __inner::_function<std::decay_t<FuncPtr>, Ret, Args...>(
  51. std::forward<std::decay_t<FuncPtr>>(funcPtr));
  52. }
  53. constexpr ~function()
  54. {
  55. _f()->~_function_base();
  56. }
  57. constexpr Ret operator()(Args... args) const
  58. {
  59. return (*_f())(std::forward<Args>(args)...);
  60. }
  61. };
  62. } // namespace std