简体   繁体   中英

Getting the number of dimensions of a std::vector/std::array

Let's say I want a class/struct type, inheriting from integral_constant<size_t, N> where N is the dimension and the dimension is achieved as follows:

template<class T>
struct dimension;

template<class T>
struct dimension<vector<T>> : integral_constant<size_t, 1> {};

template<class T>
struct dimension<vector<vector<T>>> : integral_constant<size_t, 2> {};

And then

cout << dimension<vector<int>>::value;         // 1
cout << dimension<vector<vector<int>>>::value; // 2

But obviously this is not perfect, as the number of dimensions can be a infinite (in theory). Is there a way to achieve a generic solution to this?

Suggestion: I went in this direction, but no further:

template<class T, class... Tn>
struct dimension<vector<Tn...>> : integral_constant<size_t, sizeof...(Tn)> {};

Since std::vector has other template parameters this wouldn't work.

A bit hard to define "what's a container". The below checks for value_type , iterator , and const_iterator nested typedefs. Tweak the void_t check as you want. (For instance, if you want only things that can be subscripted to be recognized as containers, then add decltype(std::declval<T&>()[0]) to the list.)

Note that dimension_impl 's specialization calls dimension . this allows you to specialize dimension for container-like things you don't want to be treated as a container ( std::string comes to mind).

template<class T> struct dimension;

namespace details {    
    template<class T, class = void>
    struct dimension_impl {
        static constexpr std::size_t value = 0;
    };

    template<class T>
    struct dimension_impl<T, std::void_t<typename T::value_type,
                                         typename T::iterator,
                                         typename T::const_iterator>> {
        static constexpr std::size_t value = 1 + dimension<typename T::value_type>::value;
    };
}

template<class T>
struct dimension : std::integral_constant<std::size_t, 
                                          details::dimension_impl<T>::value> {};

You can do this for a std::vector (note that the template parameter list of a std::vector is longer than 1):

template<typename T>
struct dimension { static constexpr std::size_t value = 0; };

template<typename T, typename... V>
struct dimension<std::vector<T, V...>>{
    static constexpr std::size_t value = 1 + dimension<T>::value;
};

This works instead for a std::array :

template<typename>
struct dimension { static constexpr std::size_t value = 0; };

template<typename T, std::size_t N>
struct dimension<std::array<T, N>>{
    static constexpr std::size_t value = 1 + dimension<T>::value;
};

It follows a minimal, working example:

#include<vector>
#include<iostream>

template<typename T>
struct dimension { static constexpr std::size_t value = 0; };

template<typename T, typename... V>
struct dimension<std::vector<T, V...>>{
    static constexpr std::size_t value = 1 + dimension<T>::value;
};

int main() {
    std::cout << dimension<std::vector<std::vector<int>>>::value << std::endl;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM