Skip to content

Commit 0442e3e

Browse files
committed
✨ Add nth_t and nth_v
Problem: - It's annoying to make a type list just to index into it. - Boost.MP11 doesn't provide `mp_at` that works on value lists. Solution: - Introduce `nth_t<Index, Ts...>` and `nth_v<Index, Vs...>` to give the nth type or value of a pack respectively.
1 parent 7ffe3f6 commit 0442e3e

File tree

5 files changed

+80
-15
lines changed

5 files changed

+80
-15
lines changed

docs/type_traits.adoc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,26 @@ NOTE: Detecting structurality of a type is not yet possible in the general case,
155155
so there are certain structural types for which this trait will be `false`. In
156156
practice those types should be rare, and there should be no false positives.
157157

158+
=== `nth_t`
159+
160+
`nth_t` is a type alias that extracts the nth element from a pack of types (starting at 0 of course):
161+
162+
[source,cpp]
163+
----
164+
// nth_t<Index, Ts...>
165+
static_assert(std::is_same_v<stdx::nth_t<1, int, float, bool>, float>);
166+
----
167+
168+
=== `nth_v`
169+
170+
`nth_v` is a `constexpr` variable template that extracts the nth element from a pack of values (starting at 0 of course):
171+
172+
[source,cpp]
173+
----
174+
// nth_v<Index, Vs...>
175+
static_assert(stdx::nth_v<1, 6, 28, 496> == 28);
176+
----
177+
158178
=== `template_for_each`
159179

160180
A xref:type_traits.adoc#_type_list_and_value_list[`type_list` or a `value_list`]

include/stdx/env.hpp

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ template <typename... Envs> struct env {
3434
CONSTEVAL static auto query(Q) noexcept {
3535
using I = boost::mp11::mp_find_if_q<boost::mp11::mp_list<Envs...>,
3636
_env::has_query<Q>>;
37-
using E = boost::mp11::mp_at<boost::mp11::mp_list<Envs...>, I>;
37+
using E = nth_t<I::value, Envs...>;
3838
return Q{}(E{});
3939
}
4040
};
@@ -61,18 +61,11 @@ template <std::size_t N> struct autowrap<str_lit_t<N>> {
6161
template <typename T> autowrap(T) -> autowrap<T>;
6262
template <std::size_t N> autowrap(str_lit_t<N>) -> autowrap<str_lit_t<N>>;
6363

64-
template <auto V> struct wrap {
65-
constexpr static auto value = V;
66-
};
67-
6864
template <typename> struct for_each_pair;
6965
template <std::size_t... Is> struct for_each_pair<std::index_sequence<Is...>> {
7066
template <auto... Args>
71-
using type = env<
72-
_env::ct_prop<boost::mp11::mp_at_c<boost::mp11::mp_list<wrap<Args>...>,
73-
2 * Is>::value.value,
74-
boost::mp11::mp_at_c<boost::mp11::mp_list<wrap<Args>...>,
75-
(2 * Is) + 1>::value.value>...>;
67+
using type = env<ct_prop<nth_v<2 * Is, Args...>.value,
68+
nth_v<(2 * Is) + 1, Args...>.value>...>;
7669
};
7770

7871
template <envlike Env = env<>>

include/stdx/function_traits.hpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include <stdx/type_traits.hpp>
4+
35
#include <boost/mp11/algorithm.hpp>
46
#include <boost/mp11/utility.hpp>
57

@@ -21,11 +23,8 @@ struct function_traits<std::function<R(Args...)>> {
2123
using decayed_args = List<std::decay_t<Args>...>;
2224
using arity = std::integral_constant<std::size_t, sizeof...(Args)>;
2325

24-
template <auto N>
25-
using nth_arg = boost::mp11::mp_at_c<args<boost::mp11::mp_list>, N>;
26-
template <auto N>
27-
using decayed_nth_arg =
28-
boost::mp11::mp_at_c<decayed_args<boost::mp11::mp_list>, N>;
26+
template <auto N> using nth_arg = nth_t<N, Args...>;
27+
template <auto N> using decayed_nth_arg = std::decay_t<nth_arg<N>>;
2928
};
3029
} // namespace detail
3130

include/stdx/type_traits.hpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
#pragma once
22

3+
#include <stdx/compiler.hpp>
4+
5+
#include <boost/mp11/algorithm.hpp>
6+
37
#include <type_traits>
48
#include <utility>
59

@@ -227,5 +231,43 @@ using shrink_t = decltype([]() -> T (*)() { return nullptr; });
227231

228232
template <typename T> using expand_t = decltype(T{}()());
229233
#endif
234+
235+
STDX_PRAGMA(diagnostic push)
236+
#ifdef __clang__
237+
STDX_PRAGMA(diagnostic ignored "-Wunknown-warning-option")
238+
STDX_PRAGMA(diagnostic ignored "-Wc++26-extensions")
239+
#endif
240+
template <unsigned int N, typename... Ts>
241+
using nth_t =
242+
#if __cpp_pack_indexing >= 202311L
243+
Ts...[N];
244+
#elif __has_builtin(__type_pack_element)
245+
__type_pack_element<N, Ts...>;
246+
#else
247+
boost::mp11::mp_at_c<type_list<Ts...>, N>;
248+
#endif
249+
STDX_PRAGMA(diagnostic pop)
250+
251+
#if __cplusplus >= 202002L
252+
namespace detail {
253+
template <auto V> struct value_wrapper {
254+
constexpr static auto value = V;
255+
};
256+
} // namespace detail
257+
258+
STDX_PRAGMA(diagnostic push)
259+
#ifdef __clang__
260+
STDX_PRAGMA(diagnostic ignored "-Wunknown-warning-option")
261+
STDX_PRAGMA(diagnostic ignored "-Wc++26-extensions")
262+
#endif
263+
template <unsigned int N, auto... Vs>
264+
constexpr auto nth_v =
265+
#if __cpp_pack_indexing >= 202311L
266+
Vs...[N];
267+
#else
268+
boost::mp11::mp_at_c<type_list<detail::value_wrapper<Vs>...>, N>::value;
269+
#endif
270+
STDX_PRAGMA(diagnostic pop)
271+
#endif
230272
} // namespace v1
231273
} // namespace stdx

test/type_traits.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,3 +258,14 @@ TEST_CASE("type shrinkage", "[type_traits]") {
258258
static_assert(std::same_as<stdx::expand_t<X>, C>);
259259
}
260260
#endif
261+
262+
TEST_CASE("nth type in pack", "[type_traits]") {
263+
static_assert(
264+
std::is_same_v<stdx::nth_t<2, bool, char, float, int>, float>);
265+
}
266+
267+
#if __cplusplus >= 202002L
268+
TEST_CASE("nth value in pack", "[type_traits]") {
269+
static_assert(stdx::nth_v<2, 0, true, 'b', 3> == 'b');
270+
}
271+
#endif

0 commit comments

Comments
 (0)