Skip to content

Latest commit

 

History

History
150 lines (114 loc) · 3.29 KB

277.md

File metadata and controls

150 lines (114 loc) · 3.29 KB
Info

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);
}

https://godbolt.org/z/n66GMfWao

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);
    }
}

https://godbolt.org/z/qavcThr9K

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

https://godbolt.org/z/466j7snqK

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>{}...}));
};
}

https://godbolt.org/z/6fb7e89fK

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

https://godbolt.org/z/jeY9qoYG4