In a dummy example of a class
typedef myStruct<myStruct<myStruct<int>>> mv;
int
is the innermost template parameter. How can I get the type of that parameter for arbitrary nesting depth?
A mechanism to acquire the innermost type
innermost<mv>::type -> int
Can this be done using template aliases (template template parameters are a missing feature here)?
In an example where my type would be
vector<vector<vector<int>>>
Is there a way to perform the same operation, given that vector
expects an extra template parameter ? Ofcourse a distinct implementation could be divised but is there a way to scale the solution for the first problem to handle these cases as well ?
A non-type template parameter must have a structural type, which is one of the following types (optionally cv-qualified, the qualifiers are ignored): the types of all base classes and non-static data members are structural types or (possibly multi-dimensional) array thereof.
An identifier that names a non-type template parameter of class type T denotes a static storage duration object of type const T, called a template parameter object, whose value is that of the corresponding template argument after it has been converted to the type of the template parameter.
To use a default parameter whose type is a template, you need to set this template parameter as optional too. Indeed, if you set it as a regular template parameter and call the function without specifying a value, the compiler can’t deduce the type for the template.
In the body of the template declaration, the name of a type parameter is a typedef-name which aliases the type supplied when the template is instantiated. Each constrained parameter P whose type-constraint is Q designating the concept C introduces a constraint-expression E according to the following rules:
Try the following. It also returns a tuple if the template has more than one element:
#include <tuple>
#include <type_traits>
template<typename T>
struct innermost_impl
{
using type = T;
};
template<template<typename> class E, typename T>
struct innermost_impl<E<T>>
{
using type = typename innermost_impl<T>::type;
};
template<template<typename...> class E, typename... Ts>
struct innermost_impl<E<Ts...>>
{
using type = std::tuple<typename innermost_impl<Ts>::type...>;
};
template<typename T>
using innermost = typename innermost_impl<T>::type;
template<class>
struct X;
static_assert(std::is_same<innermost<X<X<X<int>>>>, int>::value, "");
int main()
{
}
Building on 0x499602D2's answer, we get the following to only consider the first template parameter if ever there are several. And yes it compiles. It's also slightly simpler.
#include <tuple>
#include <type_traits>
#include <vector>
template<typename T>
struct innermost_impl
{
using type = T;
};
template<template<typename...> class E, typename Head, typename... Tail>
struct innermost_impl<E<Head, Tail...>>
{
using type = typename innermost_impl<Head>::type;
};
template<typename T>
using innermost = typename innermost_impl<T>::type;
template<class>
struct X;
static_assert(std::is_same<innermost<X<X<X<int>>>>, int>::value, "");
static_assert(
std::is_same<innermost<std::vector<X<std::vector<int>>>>, int>::value,
""
);
int main()
{
}
Note that no attempt is made to validate that the same template is used over and over.
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