c++c++11variadic-templates

template parameter packs access Nth type and Nth element


The following paper is the first proposal I found for template parameter packs.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1603.pdf

At page 16, it talks about introducing two new operators [] and <> for accessing parameter pack elements and parameter pack types.

The suggested syntax for such an operator involves two new operators: .[] to access values and .<> to access types. For instance:

template<int N, typename Tuple> struct tuple_element;
template<int N, ... Elements>
struct tuple_element<tuple<Elements...> >
{
    typedef Elements.<N> type;
};

template<int N, ... Elements>
Elements.<N>& get(tuple<Elements...>& t)
{ return t.[N]; }

template<int N, ... Elements>
const Elements.<N>& get(const tuple<Elements...>& t)
{ return t.[N]; }

So where are these operators? If there is none, what is their replacement?


Solution

  • C++11 doesn't have corresponding operators which is the reason they are proposed. With C++11 you'll need to either extract the corresponding information yourself or use a class which already does the necessary operation. The easiest approach is probably to just use std::tuple<T...> which already implements the corresponding logic.

    If you wonder how std::tuple<T...> currently implements these operations: it is basically an exercise in functional programming using a fairly bad functional programming notation. Once you know how to get the n-th type of the sequence, getting the n-th element using inheritance from base classes parameterized on index and type is fairly trivial. Implementing something like tuple_element<N, T...> could look something like this:

    template <int N, typename... T>
    struct tuple_element;
    
    template <typename T0, typename... T>
    struct tuple_element<0, T0, T...> {
        typedef T0 type;
    };
    template <int N, typename T0, typename... T>
    struct tuple_element<N, T0, T...> {
        typedef typename tuple_element<N-1, T...>::type type;
    };
    

    The actual more challenging bit in implementing something like std::tuple<T...> is conjuring up a list of indices so you got a parallel list of type and integers which can then be expanded, e.g., for a list of base classes using something like (how the internal details look exactly will differ but the basic idea of having a parallel parameters packs for the types and their indices will be somehow there):

    template <typename... T, int... I>
    class tuple_base<tuple_types<T...>, tuple_indices<I...>>:
         public tuple_field<T, I>... {
    };