Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / hana / functional / arg.hpp
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