I want to use the types of a template parameter pack as parameters to a different template, but cut off the last parameter.
For example:
template <class... Ts> struct some_template;
template <class... Ts> struct foo
{
using bar = some_template<magically_get_all_but_last(Ts)...>;
};
// I might be missing a few "typename"s, but you get the idea.
static_assert(std::is_same<foo<int, bool, std::string>::bar, some_template<int,bool> >::value);
Note that this is the opposite of getting only the last parameter.
Like function default arguments, templates can also have default arguments. For example, in the following program, the second parameter U has the default value as char.
The first template parameter is the type of elements the container stores and the second template parameter is the defaulted allocator a container of the standard template library has. Even the allocator has a default value such as in the case of a std::vector. The allocator depends on the type of elements.
However, template type parameters are not the only type of template parameters available. Template classes and functions can make use of another kind of template parameter known as a non-type parameter.
The data type variable is defined by an angled bracket in a parameter (t) and the keyword “template” in the C++ programming language. What types of templates are there in CPP? Function templates, class templates, and, as of C++14, variable templates are the three categories of templates.
Here is a simple approach which use std::tuple_element<I, Tuple>
together with std::index_sequence<sizeof...(Ts) - 1
to get all but the last type in a list of variadic arguments. Since the parameter pack for the indices is needed, there is an extra indirection which is put into a base but could be anywhere.
template <class T, class... Ts> struct foobase;
template <std::size_t... I, class... Ts>
struct foobase<std::index_sequence<I...>, Ts...> {
using bar = some_template<typename std::tuple_element<I, std::tuple<Ts...>>::type...>;
};
template <class... Ts> struct foo
: foobase<std::make_index_sequence<sizeof...(Ts) - 1>, Ts...>
{
};
Here is my solution which uses C++11:
template <typename ...P>
struct dummy {};
template <template <typename ...> class Obj, typename T, typename ...P>
struct internal;
template <template <typename ...> class Obj, typename ...P1, typename T, typename ...P2>
struct internal<Obj, dummy<P1...>, T, P2...>
{
using type = typename internal<Obj, dummy<P1..., T>, P2...>::type;
};
template <template <typename ...> class Obj, typename ...P1, typename T, typename L>
struct internal<Obj, dummy<P1...>, T, L>
{
using type = Obj<P1..., T>;
};
template <template <typename ...> class T, typename ...P>
struct subst_all_but_last
{
using type = typename internal<T, dummy<>, P...>::type;
};
Use like this:
using bar = typename subst_all_but_last<some_template, Ts...>::type;
instead of
using bar = some_template<magically_get_all_but_last(Ts)...>;
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