How to create a new tuple type from an old one and a type in boost?
boost, c++, tuples
Solution
I assume you want all this in compile time.
Here is the general explanation: concatening tuples is similar to concatening lists or arrays, is that the algorithm is the same. Here, given tuples `a` and `b`, I choosed to move the last element of `a` to the beginning of `b`, and repeat until `a` is empty.
First: base structures. The following structure keeps a parameter pack. It can be anything, for example a tuple:
template<typename... T>
struct pack
{
static const unsigned int size = sizeof...(T);
};
Note that the size of the pack is stored inside it. It is not mandatory, but it is convenient for the explanation. Boost uses the struct `boost::tuples::length<T>::value` (which is more verbose).
To access an element at i-th position, we use a structure similar to `boost::tuples::element<n, T>`:
// Get i-th element of parameter pack
// AKA 'implementation'
// Principle: the element i is the first element of the sub-array starting at indice i-1
template<int n, typename F, typename... T>
struct element_at : public element_at<n-1, T...>
{
};
template<typename F, typename... T>
struct element_at<0, F, T...>
{
typedef F type;
};
// Get i-th element of pack
// AKA 'interface' for the 'pack' structure
template<int n, typename P>
struct element
{
};
template<int n, typename... T>
struct element<n, pack<T...>>
{
typedef typename element_at<n, T...>::type type;
};
Now, we must use a low-level operation which is adding one element to a side of a pack (adding at left or at right). Here adding at left is choosed, but it is not the only choice:
// Concat at left (only for structure 'pack')
template<typename a, typename b>
struct tuple_concat_left
{
};
template<typename a, typename... b>
struct tuple_concat_left<a, pack<b...>>
{
typedef pack<a, b...> type;
};
For templates, `a` is not changed, and instead we use an indice to know what element to add. The inheritance define a 'type' typedef which is the concatenation of all indices after `n` and the other tuple (not including `n`, and in order). We just have to concatenate at left the element at indice `n`.
// Concat 2 tuples
template<typename a, typename b, int n = 0, bool ok = (n < a::size)>
struct tuple_concat : public tuple_concat<a, b, n+1>
{
typedef typename tuple_concat_left<
typename element<n, a>::type,
typename tuple_concat<a, b, n+1>::type
>::type type;
};
template<typename a, typename b, int n>
struct tuple_concat<a, b, n, false>
{
typedef b type;
};
And that's it! Live example here.
Now, for tuple specifics: you noticed I didn't used boost::tuple nor std::tuple. That is because a lot of implementations of boost tuplesdo not have access to variadic templates, so a fixed number of template parameters is used (they default to `boost::tuples::null_type`). Putting this directly with variadic templates is a headache, thus the need to have another abstraction.
I also assumed that you can use C++11 (with the `decltype` in your question). Concatening 2 tuples in C++03 is possible, but more repetitive and boring.
You can convert a `pack` to a tuple really easily: just change the `pack` definition to:
template<typename... T>
struct pack
{
static const unsigned int size = sizeof...(T);
typedef boost::tuple<T...> to_tuple; // < convert this pack to a boost::tuple
};
Problem
I have a tuple type. I want to add a element type in it to get a new tuple type. I can do it like ``` decltype tuple_cat(MyTuple, std::tuple<MyType>()) ``` However, I don't find `tuple_cat` in `boost::tuple`, how to do it in boost?