invoke.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_FUNCTIONAL_INVOKE_H_
  5. #define BASE_FUNCTIONAL_INVOKE_H_
  6. #include <type_traits>
  7. #include <utility>
  8. namespace base {
  9. namespace internal {
  10. // Helper struct and alias to deduce the class type from a member function
  11. // pointer or member object pointer.
  12. template <typename DecayedF>
  13. struct member_pointer_class {};
  14. template <typename ReturnT, typename ClassT>
  15. struct member_pointer_class<ReturnT ClassT::*> {
  16. using type = ClassT;
  17. };
  18. template <typename DecayedF>
  19. using member_pointer_class_t = typename member_pointer_class<DecayedF>::type;
  20. // Utility struct to detect specializations of std::reference_wrapper.
  21. template <typename T>
  22. struct is_reference_wrapper : std::false_type {};
  23. template <typename T>
  24. struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
  25. // Small helpers used below in internal::invoke to make the SFINAE more concise.
  26. template <typename F>
  27. const bool& IsMemFunPtr =
  28. std::is_member_function_pointer<std::decay_t<F>>::value;
  29. template <typename F>
  30. const bool& IsMemObjPtr = std::is_member_object_pointer<std::decay_t<F>>::value;
  31. template <typename F,
  32. typename T,
  33. typename MemPtrClass = member_pointer_class_t<std::decay_t<F>>>
  34. const bool& IsMemPtrToBaseOf =
  35. std::is_base_of<MemPtrClass, std::decay_t<T>>::value;
  36. template <typename T>
  37. const bool& IsRefWrapper = is_reference_wrapper<std::decay_t<T>>::value;
  38. template <bool B>
  39. using EnableIf = std::enable_if_t<B, bool>;
  40. // Invokes a member function pointer on a reference to an object of a suitable
  41. // type. Covers bullet 1 of the INVOKE definition.
  42. //
  43. // Reference: https://wg21.link/func.require#1.1
  44. template <typename F,
  45. typename T1,
  46. typename... Args,
  47. EnableIf<IsMemFunPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
  48. constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
  49. return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
  50. }
  51. // Invokes a member function pointer on a std::reference_wrapper to an object of
  52. // a suitable type. Covers bullet 2 of the INVOKE definition.
  53. //
  54. // Reference: https://wg21.link/func.require#1.2
  55. template <typename F,
  56. typename T1,
  57. typename... Args,
  58. EnableIf<IsMemFunPtr<F> && IsRefWrapper<T1>> = true>
  59. constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
  60. return (t1.get().*f)(std::forward<Args>(args)...);
  61. }
  62. // Invokes a member function pointer on a pointer-like type to an object of a
  63. // suitable type. Covers bullet 3 of the INVOKE definition.
  64. //
  65. // Reference: https://wg21.link/func.require#1.3
  66. template <typename F,
  67. typename T1,
  68. typename... Args,
  69. EnableIf<IsMemFunPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
  70. !IsRefWrapper<T1>> = true>
  71. constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
  72. return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
  73. }
  74. // Invokes a member object pointer on a reference to an object of a suitable
  75. // type. Covers bullet 4 of the INVOKE definition.
  76. //
  77. // Reference: https://wg21.link/func.require#1.4
  78. template <typename F,
  79. typename T1,
  80. EnableIf<IsMemObjPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
  81. constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
  82. return std::forward<T1>(t1).*f;
  83. }
  84. // Invokes a member object pointer on a std::reference_wrapper to an object of
  85. // a suitable type. Covers bullet 5 of the INVOKE definition.
  86. //
  87. // Reference: https://wg21.link/func.require#1.5
  88. template <typename F,
  89. typename T1,
  90. EnableIf<IsMemObjPtr<F> && IsRefWrapper<T1>> = true>
  91. constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
  92. return t1.get().*f;
  93. }
  94. // Invokes a member object pointer on a pointer-like type to an object of a
  95. // suitable type. Covers bullet 6 of the INVOKE definition.
  96. //
  97. // Reference: https://wg21.link/func.require#1.6
  98. template <typename F,
  99. typename T1,
  100. EnableIf<IsMemObjPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
  101. !IsRefWrapper<T1>> = true>
  102. constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
  103. return (*std::forward<T1>(t1)).*f;
  104. }
  105. // Invokes a regular function or function object. Covers bullet 7 of the INVOKE
  106. // definition.
  107. //
  108. // Reference: https://wg21.link/func.require#1.7
  109. template <typename F, typename... Args>
  110. constexpr decltype(auto) InvokeImpl(F&& f, Args&&... args) {
  111. return std::forward<F>(f)(std::forward<Args>(args)...);
  112. }
  113. } // namespace internal
  114. // Implementation of C++17's std::invoke. This is not based on implementation
  115. // referenced in original std::invoke proposal, but rather a manual
  116. // implementation, so that it can be constexpr.
  117. //
  118. // References:
  119. // - https://wg21.link/n4169#implementability
  120. // - https://en.cppreference.com/w/cpp/utility/functional/invoke
  121. // - https://wg21.link/func.invoke
  122. template <typename F, typename... Args>
  123. constexpr decltype(auto) invoke(F&& f, Args&&... args) {
  124. return internal::InvokeImpl(std::forward<F>(f), std::forward<Args>(args)...);
  125. }
  126. } // namespace base
  127. #endif // BASE_FUNCTIONAL_INVOKE_H_