【问题标题】:Function that can take arrays with different dimensions可以采用不同维度数组的函数
【发布时间】:2018-11-17 11:35:14
【问题描述】:

有没有一种方法可以创建一个函数,可以在不重载的情况下获取向量的任何维度?

目前我有,

someFunction(vector<int> a)
someFunction(vector<vector<int> > a)
someFunction(vector<vector<vector<int> > > a)

但是,有没有可能有一个功能:

singleFunction(<n-dimension vector>)
{
    // Get dimension of array/vector
}

【问题讨论】:

  • 制作模板?
  • 只是vector&lt;T&gt;上的模板。
  • 你在那个函数中做了什么?
  • 让我们退后一步:vector&lt;T&gt;:东西清单,有用的东西,没有更多问题。 vector&lt;vector&lt;int&gt;&gt;:列表列表;已经让你挑眉了。你确定这是正确的数据结构吗?对于进一步的嵌套,我真的不愿意相信这是解决您实际遇到的任何问题的正确方法。
  • vector&lt;vector&lt;int&gt; &gt; 的“维度”是否等于2,还是与其中一个向量或包含向量的实际大小有关?

标签: c++ multidimensional-array vector


【解决方案1】:

一个简单的模板应该可以解决这个问题。凭记忆:

template <T> singleFunction(vector<T> &t) {
    return t.size();
}

【讨论】:

  • 这将返回t 中的元素数量,而不是“维度”,即嵌套向量的数量。
  • 如果需要嵌套,我喜欢 Killzone Kid 的回答
【解决方案2】:

你可以使用递归模板函数

#include <iostream>
#include <vector>

void func(int el) {
  std::cout << el << std::endl;
}

template<typename T>
void func(std::vector<T> v) {
  for (const T& el : v) {
    func(el);
  }
}

int main() {
  std::vector<std::vector<int>> v {{1, 2}, {2, 3}};
  func(v);
  return 0;
}

它为每个元素调用它自己,直到它到达 int 类型的元素。

要获得尺寸,您可以使用相同的模式:

#include <iostream>
#include <vector>

template<typename T>
int someFunction(std::vector<T> v, int dim = 1);

template<>
int someFunction(std::vector<int> v, int dim) {
  return dim;
}

template<typename T>
int someFunction(std::vector<T> v, int dim) {
  return someFunction(T(), dim + 1);
}

template<typename T>
void singleFunction(std::vector<T> v) {
  int dim(someFunction(v));
  std::cout << dim << std::endl;
  // Do something
}

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

这里它创建了一个值类型的新对象并调用自己,直到它的值类型为int。每次它都会增加维度。

【讨论】:

  • 这是一个遍历所有元素的智能解决方案。但是您没有得到 OP 要求的“维度”。无论如何,我完全同意@Baum mit Augen 的评论:这是一个非常可疑的数据结构。
  • 虽然模板重载了非模板函数。所以不完全是问什么。
  • 我修好了。更好?
【解决方案3】:

也许您可以尝试这种方法,我认为这正是您要问的(采用自std::rank):

#include <iostream>
#include <vector>
#include <type_traits>

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

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

template<typename T>
size_t GetVectorRank(T)
{
    return vector_rank<T>::value;
}

int main()
{
    std::vector<std::vector<std::vector<std::vector<std::vector<int>>>>> v1;
    std::cout << GetVectorRank(v1) << std::endl;
    std::vector<std::vector<std::vector<int>>> v2;
    std::cout << GetVectorRank(v2) << std::endl;
    return 0;
}

当类型为std::vector&lt;T&gt; 时递归选择第二个模板,第一个模板将被选择用于其他所有内容以及递归结束时。上面的例子会返回:

5
3

演示:https://ideone.com/CLucGA

【讨论】:

  • 好收获!但是,如果您解释说它可以工作,那将是一个更好的答案,因为第二个模板比第一个模板更专业用于向量或向量,因此它将被选中,直到您达到一个简单的向量只有第一个模板适用。
  • @SergeBallesta 添加了一些解释,感谢您的建议
【解决方案4】:

您可以使用此代码获取尺寸

#include <vector>
#include <iostream>

template<unsigned N, typename T>
struct meta {
    static unsigned func() {//terminale recursion case
        return N;
    }
};

template<unsigned N, typename T>
struct meta<N, std::vector<T> > {//mid recursion case
    static unsigned func() {
        return meta<N + 1, T>::func();
    }
};

template<typename T>
unsigned func(T) { //adapter to deduce the type
    return meta<0, T>::func();
}

int main() {
  std::cout << func(std::vector<std::vector<std::vector<int> > >()) << std::endl;
  std::cout << func(std::vector<int>()) << std::endl;
  std::cout << func(int()) << std::endl;
  std::cout << func(std::vector<std::vector<std::vector<std::vector<std::vector<std::vector<int> > > > > >()) << std::endl;
  return 0;
}

会输出

3
1
0
6

【讨论】:

    【解决方案5】:

    使用C++17,您可以编写一个非常简单的解决方案:

    template<typename T >
    constexpr int func(){
      if constexpr (is_vector<typename T::value_type>::value )
       return 1+func<typename T::value_type>();
      return 1;
    }
    
    int main() {
        cout<< func<vector<vector<vector<vector<vector<int>>>>>>() <<endl;
        return 0;
    }
    

    按预期返回5

    你需要定义is_vector如下:

    template<class T>
    struct is_vector{
         static bool const value = false;   
    };
    template<class T>
    struct is_vector<std::vector<T> > {
      static bool const value = true;
    };
    

    【讨论】:

    • c++17 差点作弊
    猜你喜欢
    • 2014-11-14
    • 1970-01-01
    • 1970-01-01
    • 2013-10-03
    • 2017-07-13
    • 2020-02-08
    • 2018-05-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多