#include <cstddef>
#include <iostream>
#include <tuple>


#include <cstdint>
#include <type_traits>
#include <tuple>

template <typename T, typename Tuple> struct get_index;

template <typename T, typename... Ts>
struct get_index<T, std::tuple<T, Ts...>> : std::integral_constant<std::size_t, 0> {};

template <typename T, typename Tail, typename... Ts>
struct get_index<T, std::tuple<Tail, Ts...>> :
    std::integral_constant<std::size_t, 1 + get_index<T, std::tuple<Ts...>>::value> {};


struct A
{
    std::size_t size() { return 3; }
};

struct B
{
    std::size_t size() { return 2; }
};

struct C
{
    std::size_t size() { return 4; }
};

template <typename Tuple> struct Foo
{
    const Tuple& tuple_;
    std::array<int, std::tuple_size<Tuple>::value> array_;

    Foo(const Tuple& tuple)
        : tuple_(tuple)
    {
        std::cout << init() << '\n';
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////

    template <std::size_t INDEX = 0>
    typename std::enable_if<std::tuple_size<Tuple>::value == INDEX, std::size_t>::type init()
    {
        return 0;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////

    template <std::size_t INDEX = 0>
    typename std::enable_if<std::tuple_size<Tuple>::value != INDEX, std::size_t>::type init()
    {
        auto offset = init<INDEX + 1>();

        std::cout << "index: " << INDEX << "; offset: " << offset << '\n';

        array_[INDEX] = offset;

        return offset + std::get<INDEX>(tuple_).size();
    }

    template <typename T>
    std::size_t
    offset(const T&)
    {
        return array_[get_index<T&, Tuple>::value];
    }
};

int main()
{
    A a;
    B b;
    C c;
    auto t = std::tie(a, b, c);
    using T = decltype(t);
    Foo<T> foo(t);

    std::cout << foo.offset(a) << '\n';
    std::cout << foo.offset(b) << '\n';
    std::cout << foo.offset(c) << '\n';
}
