Info
-
Did you know that C++17 structured bindings support to custom classes can be added?
Example
struct foo {
int i{};
std::string s{};
};
template <auto N>
const auto& get(const foo& f) {
if constexpr (N == 0) {
return f.i;
} else if constexpr (N == 1) {
return f.s;
}
}
namespace std {
template <>
struct tuple_size<::foo> : integral_constant<std::size_t, 2> {};
template <std::size_t N>
struct tuple_element<N, ::foo> {
using type = decltype(get<N>(std::declval<::foo&>()));
};
} // namespace std
int main() {
auto [i, s] = foo{.i = 42, .s = "str"};
assert(42 == i);
assert("str" == s);
}
Puzzle
- Can you add structured bindings support to std::index_sequence?
namespace std {
// TODO
}
int main() {
{
auto [... Is] = std::make_index_sequence<0>{};
static_assert(sizeof...(Is) == 0);
}
{
auto [... Is] = std::make_index_sequence<3>{};
static_assert(sizeof...(Is) == 3);
static_assert(
typeid(std::tuple{std::integral_constant<std::size_t, 0>{},
std::integral_constant<std::size_t, 1>{},
std::integral_constant<std::size_t, 2>{}}) ==
typeid(std::tuple{Is...}));
}
{
auto [... Is] = std::make_index_sequence<42>{};
static_assert(sizeof...(Is) == 42);
}
}
Solutions
namespace std {
template <std::size_t N>
using index_constant = std::integral_constant<std::size_t, N>;
template <auto N, auto... Is>
auto get(index_sequence<Is...>) {
return index_constant<N>{};
}
template <auto... Is>
struct tuple_size<index_sequence<Is...>> : index_constant<sizeof...(Is)> {};
template <auto N, auto... Is>
struct tuple_element<N, index_sequence<Is...>> {
using type = index_constant<N>;
};
} // namespace std
namespace std {
template<auto N, size_t ...Ints>
auto constexpr get(const index_sequence<Ints...>&) {
return get<N>(tuple{integral_constant<size_t, Ints>{}...});
};
template<size_t ... Ints>
struct tuple_size<index_sequence<Ints...>> : integral_constant<size_t, sizeof...(Ints)> {};
template<size_t N, size_t ...Ints>
struct tuple_element<N, index_sequence<Ints...>> {
using type = decltype(get<N>(tuple{integral_constant<size_t, Ints>{}...}));
};
}
namespace stdext {
template <std::size_t... Is>
struct index_sequence : std::index_sequence<Is...> {
template <std::size_t I>
auto get() const -> std::tuple_element_t<I, index_sequence> {
return {};
}
};
namespace detail {
template <std::size_t N, class = std::make_index_sequence<N>>
struct make_index_sequence;
template <std::size_t N, auto... Is>
struct make_index_sequence<N, std::index_sequence<Is...>> {
using type = index_sequence<Is...>;
};
} // namespace detail
template <std::size_t N>
using make_index_sequence = typename detail::make_index_sequence<N>::type;
} // namespace stdext