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