如何在编译时获取多维std :: vector的深度?

我有一个函数,该函数采用多维std::vector,并且要求将深度(或维数)作为模板参数传递。与其对这个值​​进行硬编码,我想编写一个constexpr函数,该函数将使用std::vector并将深度作为unsigned integer值返回。

例如:

std::vector<std::vector<std::vector<int>>> v =
{
    { { 0,1},{ 2,3 } },{ { 4,5},{ 6,7 } },};

// Returns 3
size_t depth = GetDepth(v);

这需要在编译时完成,因为此深度将作为模板参数传递给模板函数:

// Same as calling foo<3>(v);
foo<GetDepth(v)>(v);

有什么办法吗?

zsdzjwx 回答:如何在编译时获取多维std :: vector的深度?

一个经典的模板问题。这是一个简单的解决方案,例如C ++标准库的工作方式。基本思想是拥有一个递归模板,该模板将对每个维度一一计数,对于不是向量的任何类型,其基本情况均为0。

#include <vector>
#include <type_traits>

template<typename T>
struct dimensions : std::integral_constant<std::size_t,0> {};

template<typename T>
struct dimensions<std::vector<T>> : std::integral_constant<std::size_t,1 + dimensions<T>::value> {};

template<typename T>
inline constexpr std::size_t dimensions_v = dimensions<T>::value; // (C++17)

因此,您可以像这样使用它:

dimensions<vector<vector<vector<int>>>>::value; // 3
// OR
dimensions_v<vector<vector<vector<int>>>>; // also 3 (C++17)

编辑:

好的,我已经完成了所有容器类型的常规实现。请注意,我根据表达式begin(t)将容器类型定义为具有格式正确的迭代器类型的任何类型,其中std::begin是为ADL查找而导入的,而t是类型为{{ 1}}。

这是我的代码以及注释,以解释为什么东西起作用以及我使用的测试用例。请注意,这需要C ++ 17进行编译。

T
,

假定容器是具有value_typeiterator成员类型(标准库容器满足此要求)的任何类型或C样式的数组,我们可以轻松地概括 Cruz Jean 的解决方案:

template<class T,typename = void>
struct rank : std::integral_constant<std::size_t,0> {};

// C-style arrays
template<class T>
struct rank<T[],void> 
    : std::integral_constant<std::size_t,1 + rank<T>::value> {};

template<class T,std::size_t n>
struct rank<T[n],1 + rank<T>::value> {};

// Standard containers
template<class T>
struct rank<T,std::void_t<typename T::iterator,typename T::value_type>> 
    : std::integral_constant<std::size_t,1 + rank<typename T::value_type>::value> {};

int main() {
    using T1 = std::list<std::set<std::array<std::vector<int>,4>>>;
    using T2 = std::list<std::set<std::vector<int>[4]>>;

    std::cout << rank<T1>();  // Output : 4
    std::cout << rank<T2>();  // Output : 4
}

如果需要,可以进一步限制容器类型。

,

您可以定义以下与任何类型匹配的类模板vector_depth<>

template<typename T>
struct vector_depth {
   static constexpr size_t value = 0;
};

此主模板对应于结束递归的基本情况。然后,为std::vector<T>定义其对应的专业化:

template<typename T>
struct vector_depth<std::vector<T>> {
   static constexpr size_t value = 1 + vector_depth<T>::value;
};

此专业匹配std::vector<T>并对应于递归情况。

最后,定义函数模板GetDepth(),该函数模板采用上述类模板:

template<typename T>
constexpr auto GetDepth(T&&) {
   return vector_depth<std::remove_cv_t<std::remove_reference_t<T>>>::value;
}

示例:

auto main() -> int {
   int a{}; // zero depth
   std::vector<int> b;
   std::vector<std::vector<int>> c;
   std::vector<std::vector<std::vector<int>>> d;

   // constexpr - dimension determinted at compile time
   constexpr auto depth_a = GetDepth(a);
   constexpr auto depth_b = GetDepth(b);
   constexpr auto depth_c = GetDepth(c);
   constexpr auto depth_d = GetDepth(d);

   std::cout << depth_a << ' ' << depth_b << ' ' << depth_c << ' ' << depth_d;
}

该程序的输出为:

0 1 2 3
本文链接:https://www.f2er.com/2857509.html

大家都在问