arg.hpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /*!
  2. @file
  3. Defines `boost::hana::arg`.
  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_ARG_HPP
  9. #define BOOST_HANA_FUNCTIONAL_ARG_HPP
  10. #include <boost/hana/config.hpp>
  11. #include <cstddef>
  12. #include <type_traits>
  13. BOOST_HANA_NAMESPACE_BEGIN
  14. //! @ingroup group-functional
  15. //! Return the `n`th passed argument.
  16. //!
  17. //! Specifically, `arg<n>(x1, ..., xn, ..., xm)` is equivalent to `xn`.
  18. //! Note that indexing starts at 1, so `arg<1>` returns the 1st argument,
  19. //! `arg<2>` the 2nd and so on. Using `arg<0>` is an error. Passing
  20. //! less than `n` arguments to `arg<n>` is also an error.
  21. //!
  22. //!
  23. //! @tparam n
  24. //! An unsigned integer representing the argument to return. `n` must be
  25. //! positive (meaning nonzero).
  26. //!
  27. //! @param x1, ..., xm
  28. //! A variadic pack of arguments from which the `n`th one is returned.
  29. //!
  30. //!
  31. //! @internal
  32. //! ### Discussion: could `n` be dynamic?
  33. //! We could have chosen `arg` to be used like `arg(n)(x...)` instead of
  34. //! `arg<n>(x...)`. Provided all the arguments were of the same type, it
  35. //! would then be possible for `n` to only be known at runtime. However,
  36. //! we would then lose the ability to assert the in-boundedness of `n`
  37. //! statically.
  38. //!
  39. //! ### Rationale for `n` being a non-type template parameter
  40. //! I claim that the only interesting use case is with a compile-time
  41. //! `n`, which means that the usage would become `arg(int_<n>)(x...)`,
  42. //! which is more cumbersome to write than `arg<n>(x...)`. This is open
  43. //! for discussion.
  44. //! @endinternal
  45. //!
  46. //! ### Example
  47. //! @include example/functional/arg.cpp
  48. #ifdef BOOST_HANA_DOXYGEN_INVOKED
  49. template <std::size_t n>
  50. constexpr auto arg = [](auto&& x1, ..., auto&& xm) -> decltype(auto) {
  51. return forwarded(xn);
  52. };
  53. #else
  54. template <std::size_t n, typename = void>
  55. struct arg_t;
  56. template <>
  57. struct arg_t<1> {
  58. template <typename X1, typename ...Xn>
  59. constexpr X1 operator()(X1&& x1, Xn&& ...) const
  60. { return static_cast<X1&&>(x1); }
  61. };
  62. template <>
  63. struct arg_t<2> {
  64. template <typename X1, typename X2, typename ...Xn>
  65. constexpr X2 operator()(X1&&, X2&& x2, Xn&& ...) const
  66. { return static_cast<X2&&>(x2); }
  67. };
  68. template <>
  69. struct arg_t<3> {
  70. template <typename X1, typename X2, typename X3, typename ...Xn>
  71. constexpr X3 operator()(X1&&, X2&&, X3&& x3, Xn&& ...) const
  72. { return static_cast<X3&&>(x3); }
  73. };
  74. template <>
  75. struct arg_t<4> {
  76. template <typename X1, typename X2, typename X3, typename X4, typename ...Xn>
  77. constexpr X4 operator()(X1&&, X2&&, X3&&, X4&& x4, Xn&& ...) const
  78. { return static_cast<X4&&>(x4); }
  79. };
  80. template <>
  81. struct arg_t<5> {
  82. template <typename X1, typename X2, typename X3, typename X4,
  83. typename X5, typename ...Xn>
  84. constexpr X5 operator()(X1&&, X2&&, X3&&, X4&&, X5&& x5, Xn&& ...) const
  85. { return static_cast<X5&&>(x5); }
  86. };
  87. template <std::size_t n, typename>
  88. struct arg_t {
  89. static_assert(n > 0,
  90. "invalid usage of boost::hana::arg<n> with n == 0");
  91. template <typename X1, typename X2, typename X3, typename X4,
  92. typename X5, typename ...Xn>
  93. constexpr decltype(auto)
  94. operator()(X1&&, X2&&, X3&&, X4&&, X5&&, Xn&& ...xn) const {
  95. static_assert(sizeof...(xn) >= n - 5,
  96. "invalid usage of boost::hana::arg<n> with too few arguments");
  97. // Since compilers will typically try to continue for a bit after
  98. // an error/static assertion, we must avoid sending the compiler
  99. // in a very long computation if n == 0.
  100. return arg_t<n == 0 ? 1 : n - 5>{}(static_cast<Xn&&>(xn)...);
  101. }
  102. };
  103. template <std::size_t n>
  104. struct arg_t<n, std::enable_if_t<(n > 25)>> {
  105. template <
  106. typename X1, typename X2, typename X3, typename X4, typename X5,
  107. typename X6, typename X7, typename X8, typename X9, typename X10,
  108. typename X11, typename X12, typename X13, typename X14, typename X15,
  109. typename X16, typename X17, typename X18, typename X19, typename X20,
  110. typename X21, typename X22, typename X23, typename X24, typename X25,
  111. typename ...Xn>
  112. constexpr decltype(auto)
  113. operator()(X1&&, X2&&, X3&&, X4&&, X5&&,
  114. X6&&, X7&&, X8&&, X9&&, X10&&,
  115. X11&&, X12&&, X13&&, X14&&, X15&&,
  116. X16&&, X17&&, X18&&, X19&&, X20&&,
  117. X21&&, X22&&, X23&&, X24&&, X25&&, Xn&& ...xn) const
  118. { return arg_t<n - 25>{}(static_cast<Xn&&>(xn)...); }
  119. };
  120. template <std::size_t n>
  121. constexpr arg_t<n> arg{};
  122. #endif
  123. BOOST_HANA_NAMESPACE_END
  124. #endif // !BOOST_HANA_FUNCTIONAL_ARG_HPP