How to create a new type of tuple from the old and type in boost?

I have a type of tuple. I want to add an element type to it to get a new tuple type. I can do it like

decltype tuple_cat(MyTuple, std::tuple<MyType>()) 

However, I did not find tuple_cat in boost::tuple , how to do it in boost?

+8
c ++ boost tuples
source share
2 answers

I assume you want all this at compile time.

Here is a general explanation: tuple binding is similar to concatenating lists or arrays; the algorithm is the same. Here, given tuples a and b , I decided to move the last element of a to the beginning of b and repeat until a is empty.

First: basic structures. The following structure stores a package of parameters. It can be anything, for example a tuple:

 template<typename... T> struct pack { static const unsigned int size = sizeof...(T); }; 

Please note that the packet size is stored inside it. This is not necessary, but it is convenient for explanation. Boost uses struct boost::tuples::length<T>::value (more verbose).

To access the element in the 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 need to use a low-level operation that adds one element to the side of the package (adding left or right). Here the add on the left is selected, but this 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 does not change, and instead we use an index to find out which element to add. Inheritance defines a “type” of typedef, which is the concatenation of all indices after n and another tuple (not including n and in order). We just need to concatenate the element at index n on the left.

 // 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 this! Real-time example here .

Now, for the features of the set: you noticed that I did not use boost :: tuple or std :: tuple. This is due to the fact that many boost tuplesdo implementations do not have access to variational templates, therefore a fixed number of template parameters are used (they are equal to boost::tuples::null_type ). Including this directly in variable templates is a headache, so you need to have a different abstraction.

I also suggested that you can use C ++ 11 (with decltype in your question). Merging two tuples in C ++ 03 is possible, but more repetitive and boring.

You can easily convert pack to tuple: just change the definition of pack 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 }; 
+6
source share

C ++ 14 offers a library for generating a sequence of integers in the compiler. This helps control static sequences, such as tuples and arrays ( example ). The whole sequence can be obtained.

 template<size_t... Ints> struct integer_sequence {}; template<size_t Size, size_t... Ints> struct implementation : implementation<Size-1, Size-1, Ints...> {}; template<size_t... Ints> struct implementation<0, Ints...> { typedef integer_sequence<Ints...> type; }; template<class... T> using index_sequence_for = typename implementation<sizeof...(T)>::type; 

For concat MyTuple and MyType you can write simple functions:

 template<typename X, typename Tuple, size_t... Ints> auto concat(X x, Tuple t, integer_sequence<Ints...>) -> decltype( std::make_tuple(x, std::get<Ints>(t)...) ) { return std::make_tuple(x, std::get<Ints>(t)...); } template<typename X, typename... T> std::tuple<X, T...> concat(X x, std::tuple<T...> t) { return concat(x, t, index_sequence_for<T...>()); } concat(MyType, MyTuple); 
+1
source share

All Articles