overload_linearly.hpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /*!
  2. @file
  3. Defines `boost::hana::overload_linearly`.
  4. @copyright Louis Dionne 2013-2017
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_HANA_FUNCTIONAL_OVERLOAD_LINEARLY_HPP
  9. #define BOOST_HANA_FUNCTIONAL_OVERLOAD_LINEARLY_HPP
  10. #include <boost/hana/config.hpp>
  11. #include <boost/hana/detail/decay.hpp>
  12. #include <utility>
  13. BOOST_HANA_NAMESPACE_BEGIN
  14. //! @ingroup group-functional
  15. //! Call the first function that produces a valid call expression.
  16. //!
  17. //! Given functions `f1, ..., fn`, `overload_linearly(f1, ..., fn)` is
  18. //! a new function that calls the first `fk` producing a valid call
  19. //! expression with the given arguments. Specifically,
  20. //! @code
  21. //! overload_linearly(f1, ..., fn)(args...) == fk(args...)
  22. //! @endcode
  23. //!
  24. //! where `fk` is the _first_ function such that `fk(args...)` is a valid
  25. //! expression.
  26. //!
  27. //!
  28. //! Example
  29. //! -------
  30. //! @include example/functional/overload_linearly.cpp
  31. #ifdef BOOST_HANA_DOXYGEN_INVOKED
  32. constexpr auto overload_linearly = [](auto&& f1, auto&& f2, ..., auto&& fn) {
  33. return [perfect-capture](auto&& ...x) -> decltype(auto) {
  34. return forwarded(fk)(forwarded(x)...);
  35. };
  36. };
  37. #else
  38. template <typename F, typename G>
  39. struct overload_linearly_t {
  40. F f;
  41. G g;
  42. private:
  43. template <typename ...Args, typename =
  44. decltype(std::declval<F const&>()(std::declval<Args>()...))>
  45. constexpr F const& which(int) const& { return f; }
  46. template <typename ...Args, typename =
  47. decltype(std::declval<F&>()(std::declval<Args>()...))>
  48. constexpr F& which(int) & { return f; }
  49. template <typename ...Args, typename =
  50. decltype(std::declval<F&&>()(std::declval<Args>()...))>
  51. constexpr F which(int) && { return static_cast<F&&>(f); }
  52. template <typename ...Args>
  53. constexpr G const& which(long) const& { return g; }
  54. template <typename ...Args>
  55. constexpr G& which(long) & { return g; }
  56. template <typename ...Args>
  57. constexpr G which(long) && { return static_cast<G&&>(g); }
  58. public:
  59. template <typename ...Args>
  60. constexpr decltype(auto) operator()(Args&& ...args) const&
  61. { return which<Args...>(int{})(static_cast<Args&&>(args)...); }
  62. template <typename ...Args>
  63. constexpr decltype(auto) operator()(Args&& ...args) &
  64. { return which<Args...>(int{})(static_cast<Args&&>(args)...); }
  65. template <typename ...Args>
  66. constexpr decltype(auto) operator()(Args&& ...args) &&
  67. { return which<Args...>(int{})(static_cast<Args&&>(args)...); }
  68. };
  69. struct make_overload_linearly_t {
  70. template <typename F, typename G>
  71. constexpr overload_linearly_t<
  72. typename detail::decay<F>::type,
  73. typename detail::decay<G>::type
  74. > operator()(F&& f, G&& g) const {
  75. return {static_cast<F&&>(f), static_cast<G&&>(g)};
  76. }
  77. template <typename F, typename G, typename ...H>
  78. constexpr decltype(auto) operator()(F&& f, G&& g, H&& ...h) const {
  79. return (*this)(static_cast<F&&>(f),
  80. (*this)(static_cast<G&&>(g), static_cast<H&&>(h)...));
  81. }
  82. template <typename F>
  83. constexpr typename detail::decay<F>::type operator()(F&& f) const {
  84. return static_cast<F&&>(f);
  85. }
  86. };
  87. constexpr make_overload_linearly_t overload_linearly{};
  88. #endif
  89. BOOST_HANA_NAMESPACE_END
  90. #endif // !BOOST_HANA_FUNCTIONAL_OVERLOAD_LINEARLY_HPP