It is possible to get the first element of the parameter pack like this
template <typename... Elements>
struct type_list
{
};
template <typename TypeList>
struct type_list_first_element
{
};
template <typename FirstElement, typename... OtherElements>
struct type_list_first_element<type_list<FirstElement, OtherElements...>>
{
typedef FirstElement type;
};
int main()
{
typedef type_list<int, float, char> list;
typedef type_list_first_element<list>::type element;
return 0;
}
but not possible to similary get the last element like this
template <typename... Elements>
struct type_list
{
};
template <typename TypeList>
struct type_list_last_element
{
};
template <typename LastElement, typename... OtherElements>
struct type_list_last_element<type_list<OtherElements..., LastElement>>
{
typedef LastElement type;
};
int main()
{
typedef type_list<int, float, char> list;
typedef type_list_last_element<list>::type element;
return 0;
}
with gcc 4.7.1 complaining:
error: 'type' in 'struct type_list_last_element<type_list<int, float, char>>' does not name a type
What paragraps from the standard describe this behaviour?
It seems to me that template parameter packs are greedy in a sense that they consume all matching arguments, which in this case means that OtherElements
consumes all three arguments (int
, float
and char
) and then there is nothing left for LastElement
so the compilation fails. Am i correct in the assumption?
EDIT:
To clarify: I am not asking how to extract the last element from the parameter pack, i know how to do that. What i actually want is to pick the pack apart from the back as opposed to the front, and as such recursing all the way to the back for each element would be ineffective. Apparentely reversing the sequence beforehand is the most sensible choice.
The relevant clause is the bullet at the end of 14.5.5:8:
14.5.5 Class template partial specializations [temp.class.spec]
8 - Within the argument list of a class template partial specialization, the following restrictions apply: [...]
- An argument shall not contain an unexpanded parameter pack. If an argument is a pack expansion (14.5.3), it shall be the last argument in the template argument list.
Observation:
<first,...>
is the same as last element of <...>
if only ...
is not empty. <elem>
is elem
So you have to do it recursively, with tail template:
Recursion:
template <typename TypeList>
struct type_list_last_element;
template <typename FirstElement, typename... OtherElements>
struct type_list_last_element<type_list<FirstElement, OtherElements...>>
{
typedef typename type_list_last_element<type_list<OtherElements...>>::type type;
};
Tail:
template <typename LastElement>
struct type_list_last_element<type_list<LastElement>>
{
typedef LastElement type;
};
[UPDATE] And usage:
int main()
{
typedef type_list<int, float, char> list;
typedef type_list_last_element<list>::type last;
return 0;
}
[END UPDATE]
See ideone
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With