C++ Tuples: the missing functionality

C++ provides a strange mix of compile-time and runtime functionality for dealing with tuples. There are some interesting parts, like std::tie to destructure a tuple, and std::tuple_cat to join together several tuples into one. So there is evidence that the standard has been influenced by some functional programming ideas, but I don’t think the full power of tuples has been realized (in both senses), and I found myself thinking about some missing parts.

Like why do we have std::tuple_cat and std::get<0> (aka std::tuple_head), but not std::tuple_cons or std::tuple_tail? So here are some possible implementations.

First, something missing from type_traits which will help us constrain things:

template 
struct is_tuple : public std::false_type {};

template 
struct is_tuple> : public std::true_type {};

Both tuple_cons and tuple_tail can make use of an expansion of std::index_sequence to work their magic, with a user-facing function that provides the appropriate std::index_sequence to an overload.

For tuple_cons, we just call std::make_tuple with the new element and the result of expanding std::get across the other tuple:

template 
auto tuple_cons(U&& u, T&& t, std::index_sequence,
    std::enable_if_t>::value>* = nullptr)
{
  return std::make_tuple(std::forward(u), 
                         std::get(std::forward(t))...);
}

template 
auto tuple_cons(U&& u, T&& t,
    std::enable_if_t>::value>* = nullptr)
{
  using Tuple = std::decay_t;
  return tuple_cons(std::forward(u), std::forward(t),
      std::make_index_sequence::value>());
}

And for tuple_tail, we construct a std::index_sequence of length n-1, then offset it by one in the expansion to obtain the tail:

template 
auto tuple_tail(T&& t, std::index_sequence,
    std::enable_if_t>::value>* = nullptr)
{
  return std::make_tuple(std::get(std::forward(t))...);
}

template 
auto tuple_tail(T&& t, 
    std::enable_if_t>::value>* = nullptr)
{
  using Tuple = std::decay_t;
  return tuple_tail(std::forward(t),
      std::make_index_sequence::value - 1>());
}

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.