Search code examples
c++templatesc++14template-meta-programming

How can I deduce the inner type of a nested std::vector at compile time?


The other day I asked a very similar question about nested vectors, but I've come across another problem that has me stumped. I need to get the innermost type of a nested vector at compile time so I can use it to pass as a template argument.

For example if I have this nested vector:

std::vector<std::vector<std::vector<int>>> v;

I need a way to extract int so I can call a function that takes a nested vector and works on the elements like this:

foo<int>(v);

Except the catch is this function should be able to work on nested vectors of any depth that hold any type. And when I call foo I want the inner type to be automatically deduced for me.

So maybe the call would look something like this:

foo<inner_type_t<v>>(v);

Where inner_type_t is some form of recursive template that resolves to int when given v.

I assume the solution will be similar to that of the other question but I haven't been able to work it out... I'm still a bit of a novice when it comes to recursive templates.

Edit:

Here is what I have so far...

template <typename T>
struct inner_type
{
    using type = T;
};

template <typename T>
struct inner_type<std::vector<T>>
{
    using type = inner_type<T>;
};

int main()
{
    std::vector<std::vector<int>> v  = {
        { 1, 2}, {3, 4}
    };

    std::cout << typeid(inner_type<decltype(v)>::type).name();
}

output:

struct inner_type<class std::vector<int,class std::allocator<int> > >

Solution

  • @tjwrona1992's solution is ok, but doesn't allow for vectors with different allocators. Also, let's make this C++14-friendly with an _t version of the trait.

    This should do the trick:

    template <typename T> struct inner_type { using type = T; };
    
    template<class T, class Alloc>
    struct inner_type<std::vector<T, Alloc>> { using type = typename inner_type<T>::type; };
    
    template<class T>
    using inner_type_t = typename inner_type<T>::type;
    

    Also, for the type name, you should using the type_name() function implemented here for C++14 or here for C++17.

    See it working live...