meguli
meguli

Reputation: 1526

Making an index sequence for tuple implementation

Suppose I want to implement something like std::tuple myself, just the basics. I want to show a failed attempt first.

#include <utility>
#include <iostream>

template <std::size_t I>
struct tuple_index_leaf {
    using Index = std::integral_constant<std::size_t, I>;
    std::size_t i = Index::value;
};

template <std::size_t... Is>
struct tuple_index : tuple_index_leaf<Is>...
{};

template <std::size_t I, std::size_t... Is>
constexpr auto get_index(tuple_index<Is...> const &i) {
    return static_cast<const tuple_index_leaf<I>*>(&i)->i;
}

template <std::size_t I, typename T>
struct tuple_leaf : tuple_index_leaf<I> {
    T elem;
};

template<typename... Ts>
struct tuple : tuple_leaf<sizeof...(Ts), Ts>... {

};

template <std::size_t I, typename... Ts>
auto& get(tuple<Ts...> &t) {
    return static_cast<tuple_leaf<I, float>*>(&t)->elem;
}

int main() {
    tuple_index<0, 1, 2> ti;
    std::cout << get_index<0>(ti) << "\n";
    tuple<int, float> t;
    get<2>(t) = 3.14;
} 

Now, take a look at get function. I hard coded the last type float and I can only call this with index 2, like get<2>. This is because the deficiency in my tuple constructor. If you look there, you will see that I am passing sizeof...(Ts) to tuple_leaf. For example, in this case, all my tuple leaves will be like tuple_leaf<2, int>, tuple_leaf<2, float>. What I wanted was an expansion like tuple_leaf<0, int>, tuple_leaf<1, float>.... The expansion I used, tuple_leaf<sizeof...(Ts), Ts>... does not give me these, I know. I need some sort of index sequence I figured and started implementing something like tuple_index. But that one requires me to pass std::size_t... and I don't know how to do that. So the question is, how can I get an expansion like tuple_leaf<0, int>, tuple_leaf<1, float>...?

Upvotes: 2

Views: 555

Answers (1)

SergeyA
SergeyA

Reputation: 62563

It is not hard. Here is one example how to do this (not claiming the only one way, this was something I put together quickly):

#include <utility>
#include <cstddef>

template <std::size_t I, typename T>
struct tuple_leaf {
    T elem;
};

template<class SEQ, class... TYPE> struct tuple_impl;

template<size_t... Ix, class... TYPE>
struct tuple_impl<std::index_sequence<Ix...>, TYPE...> : tuple_leaf<Ix, TYPE>... { };

template<typename... Ts>
struct tuple : tuple_impl<std::make_index_sequence<sizeof...(Ts)>, Ts...> { };


// below lines are for testing
tuple<int, double, char*> tup;

// the fact that this compiles tells us char* has index 2
auto& z = static_cast<tuple_leaf<2, char*>&>(tup);

Upvotes: 2

Related Questions