Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the innermost template parameter type?

Q

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?

Desired Result

A mechanism to acquire the innermost type

innermost<mv>::type -> int

WishList

  1. Can this be done using template aliases (template template parameters are a missing feature here)?

  2. 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 ?

like image 672
Nikos Athanasiou Avatar asked Aug 07 '14 16:08

Nikos Athanasiou


People also ask

What is a non-type template parameter?

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.

What is a template parameter in C++?

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.

How to use a default parameter whose type is a template?

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.

How do you name a parameter in a 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:


2 Answers

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()
{
}
like image 56
David G Avatar answered Oct 12 '22 12:10

David G


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.

like image 34
Matthieu M. Avatar answered Oct 12 '22 12:10

Matthieu M.