With C++17, the cleanest way is
template<typename T>
struct tag
{
using type = T;
};
template<typename... Ts>
struct select_last
{
// Use a fold-expression to fold the comma operator over the parameter pack.
using type = typename decltype((tag<Ts>{}, ...))::type;
};
with O(1) instantiation depth.