I know how to select first parameter of variadic template:
template< class...Args> struct select_first;
template< class A, class ...Args> struct
A pretty dumb approach would be to write a helper class and specialize for each number of parameters (up to some limit of your choice). You could use preprocessor for that.
template<typename...>
struct select_last_helper;
template<typename T1>
struct select_last_helper<T1> {
using type = T1;
};
template<typename T1, typename T2>
struct select_last_helper<T1,T2> {
using type = T2;
};
template<typename T1, typename T2, typename T3>
struct select_last_helper<T1,T2,T3> {
using type = T3;
};
template<typename... Ts>
struct select_last {
using type = typename select_last_helper<Ts...>::type;
};
O(1) template instantiations :)
This other solution is brilliant if C++17 is available and if one is interested in the last type only.
If C++14 support is required (C++11 plus index_sequence) or if one is interested in the nth type then a good solution is
#include <utility>
////////////////////////////////////////////////////////////////////////////////
template<std::size_t n, std::size_t i, class>
struct type_if_equal {
static_assert(n != i, "see specialization");
// missing `type` typedef by purpose
};
template<std::size_t n, class T>
struct type_if_equal<n, n, T> {
using type = T;
};
////////////////////////////////////////////////////////////////////////////////
template<std::size_t n, class Is, class... Ts>
struct select_nth;
template<std::size_t n, std::size_t... is, class... Ts>
struct select_nth<n, std::index_sequence<is...>, Ts...>
: type_if_equal<n, is, Ts>...
{};
template<std::size_t n, class... Ts>
using select_nth_t = typename select_nth<
n, std::index_sequence_for<Ts...>, Ts...
>::type;
////////////////////////////////////////////////////////////////////////////////
template<class T0, class... Ts>
using select_last_t = select_nth_t<sizeof...(Ts), T0, Ts...>;
////////////////////////////////////////////////////////////////////////////////
int main() {
using T = select_last_t<int, double, double, long, long, long, int, char>;
static_assert(std::is_same<T, char>{}, "");
}
Warning: Do not use a naive self-made solution like select_nth_t if you need fast compilation times for huge variadic lists. There are highly optimized template-metaprogramming libraries for this purpose. Have a look at metaben.ch for a comparison of compile-time performance of several algorithms. This algorithm is called at, and here is my measurement result of select_nth_t based on this code using GCC 10:
See blog posts by Louis Dionne and Odin Holmes for excellent background information regarding compile-time reduction of the at algorithm (a.k.a. std::tuple_element_t).