callable_wrapper.hpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /* Copyright 2016-2017 Joaquin M Lopez Munoz.
  2. * Distributed under the Boost Software License, Version 1.0.
  3. * (See accompanying file LICENSE_1_0.txt or copy at
  4. * http://www.boost.org/LICENSE_1_0.txt)
  5. *
  6. * See http://www.boost.org/libs/poly_collection for library home page.
  7. */
  8. #ifndef BOOST_POLY_COLLECTION_DETAIL_CALLABLE_WRAPPER_HPP
  9. #define BOOST_POLY_COLLECTION_DETAIL_CALLABLE_WRAPPER_HPP
  10. #if defined(_MSC_VER)
  11. #pragma once
  12. #endif
  13. #include <boost/poly_collection/detail/is_invocable.hpp>
  14. #include <functional>
  15. #include <type_traits>
  16. #include <typeinfo>
  17. namespace boost{
  18. namespace poly_collection{
  19. namespace detail{
  20. /* lightweight std::function look-alike over non-owned callable entities */
  21. template<typename Signature>
  22. class callable_wrapper;
  23. template<typename R,typename... Args>
  24. class callable_wrapper<R(Args...)>
  25. {
  26. public:
  27. // TODO: we should prevent assignment by user code
  28. template<
  29. typename Callable,
  30. typename std::enable_if<
  31. !std::is_same<Callable,callable_wrapper>::value&&
  32. is_invocable_r<R,Callable,Args...>::value
  33. >::type* =nullptr
  34. >
  35. explicit callable_wrapper(Callable& x)noexcept:pt{info(x)},px{&x}{}
  36. callable_wrapper(const callable_wrapper&)=default;
  37. callable_wrapper& operator=(const callable_wrapper&)=default;
  38. explicit operator bool()const noexcept{return true;}
  39. R operator()(Args... args)const
  40. {return pt->call(px,std::forward<Args>(args)...);}
  41. const std::type_info& target_type()const noexcept{return pt->info;}
  42. template<typename T>
  43. T* target()noexcept
  44. {return typeid(T)==pt->info?static_cast<T*>(px):nullptr;}
  45. template<typename T>
  46. const T* target()const noexcept
  47. {return typeid(T)==pt->info?static_cast<const T*>(px):nullptr;}
  48. /* not in std::function interface */
  49. operator std::function<R(Args...)>()const noexcept{return pt->convert(px);}
  50. void* data()noexcept{return px;}
  51. const void* data()const noexcept{return px;}
  52. private:
  53. struct table
  54. {
  55. R(*call)(void*,Args...);
  56. const std::type_info& info;
  57. std::function<R(Args...)> (*convert)(void*);
  58. };
  59. template<typename Callable>
  60. static table* info(Callable&)noexcept
  61. {
  62. static table t={
  63. [](void* p,Args... args){
  64. auto r=std::ref(*static_cast<Callable*>(p));
  65. return static_cast<R>(r(std::forward<Args>(args)...));
  66. },
  67. typeid(Callable),
  68. [](void* p){
  69. auto r=std::ref(*static_cast<Callable*>(p));
  70. return std::function<R(Args...)>{r};
  71. }
  72. };
  73. return &t;
  74. }
  75. table* pt;
  76. void* px;
  77. };
  78. } /* namespace poly_collection::detail */
  79. } /* namespace poly_collection */
  80. } /* namespace boost */
  81. #endif