【问题标题】:C++ metaprograming detect size arrayC ++元编程检测大小数组
【发布时间】:2013-06-02 15:24:28
【问题描述】:

我必须制作一个元编程模板,我必须在其中检测数组的大小。 所以检测数组大小的模板:

template<typename T, size_t N>
size_t arraylen( T(&)[N] )
{ return N; }

这很好用,但是在这个模板上也可以工作

//Template to calculate Vector*Vector
template<int N>  double IloczynSkalarny(double *a,double *b) {
  return (*a)*(*b)+IloczynSkalarny<N-1>(++a,++b);
}
template<>  double IloczynSkalarny<1>(double *a,double *b) {
  return (*a)*(*b);
}
//Here we calculate the row of matrix using Vector*Vector template
template<int M,size_t I> double row_vec(double *A,double *v) {
  return IloczynSkalarny<M>(A+I*M,v);
}

//Looping thru matrix rows
template<int N,int M> struct  matrix_vec_c {
  static void matrix_vec(double *A,double *v,double *u) {
    u[N-1]=row_vec<M,N-1>(A,v);
    matrix_vec_c<N-1,M>::matrix_vec(A,v,u);
  }
};

template<int M> struct  matrix_vec_c<0,M> {
  static void matrix_vec(double *A,double *v,double *u) {}
};


//Calling template
template<size_t N,size_t M> inline void matrix_vec(double A[],double v[],double u[]) {
  matrix_vec_c<N,M>::matrix_vec(A,v,u);
}

当我像这样给出参数 N i M 时,这个模板效果很好

double x[] = {1, 1, 0};
double A[] = {1, 0, 0,

              2, -5, 1};
double y[2];
matrix_vec<2,3>(A,x,y);

但我需要像这样调用 matrix_vec:

matrix_vec(A,x,y);

没有 N i M 参数传递给模板。所以我必须检测数组的大小。 所以我制作这样的模板:

inline void matrix_vec(double A[],double v[],double u[]) {
  int  N = arraylen(v);
  int M = arraylen(u);
 matrix_vec_c<N,M>::matrix_vec(A,v,u);
}

但我得到错误:没有匹配函数调用'arraylen(double*&)'

当我输入 N i M 的 const 值时,它的工作原理:

inline void matrix_vec(double A[],double v[],double u[]) {
  int const N = 3;
  int const M = 3;
 matrix_vec_c<N,M>::matrix_vec(A,v,u);
}

这当然没有意义,因为传递的数组有不同的大小。 模板函数 arraylen 工作正常,但在我的模板中我做错了什么?

PS 数组是 C 风格的,没有像 std::vector 或其他的 C++

【问题讨论】:

  • return (*a)*(*b)+IloczynSkalarny&lt;N-1&gt;(++a,++b); 这是未定义的行为。
  • 但是这个模板工作正常我没有这个模板的问题。
  • 未定义的行为并不意味着它不会编译。相反,它可能不会按照您的预期去做,或者在看似随机的情况下失败。
  • @Aku 无论如何,你应该修复它。如果它被另一个编译器、另一个版本的编译器或不同的优化级别搞砸了,请不要感到惊讶。

标签: c++ arrays size detect template-meta-programming


【解决方案1】:

这至少是首先使用这个模板的一个重要部分——它只有在传递一个实际数组时才会起作用。当您尝试在函数内部使用它时,函数参数已经从数组衰减为指针。由于不能在指针上调用模板,因此编译失败。

为了使事情正常工作,您可以(例如)将函数制作成一个模板,该模板也接收对数组的引用。这会将参数的“数组”性质保留到函数本身中(就像它在模板中所做的那样)。

template <class T, size_t N>
size_t sum(T(&matrix)[N]) { 
    // use matrix. For this example, we'll sum its elements:
    size_t total = 0;
    for (size_t i=0; i<N; i++)
        total += matrix[i];
    return total;
}

你可以使用这样的东西:

int main() { 
    int x[] = {1, 3, 5, 7, 9};
    std::cout << sum(x);
    return 0;
}

但是请注意,在这种情况下,您实际上并不需要您的 arraylen,因为数组 (N) 的大小是直接可用的。

另一种让它工作的方法(更好的方法,IMO)就是对数组说不。例如,传递一个std::vector,整个问题就完全消失了——你不需要一个特殊的模板技巧来获得长度,你只需调用your_vector.size()就可以了。

【讨论】:

  • 我知道 std::vector 和 C++ 的东西是更好的方法,但这里的数组是 C 风格的。
  • 此代码导致编译错误:在 ')' 标记之前预期的 unqualified-id。在线类 matrix_vec(T(&matrix)[N]) {
  • @Aku:哎呀——非常正确。我写的是模板类和模板函数的某种混淆混合物,两者都不起作用。我相信我现在已经纠正了。
【解决方案2】:

这是因为当您将数组传递给函数时,它们不再是数组而是衰减为指针。数组和指针几乎可以互换,但区别在于指针当然没有大小。

【讨论】:

  • 那么在这种情况下我必须如何检测数组的大小?
  • @Aku 你不能,反正不使用普通数组。我建议您开始查看std::vectorstd::array
  • 但是任务规范是传递一个数组,这个数组是 C 风格的,不像 C++ 数组和 STL 容器。
  • @Aku 然后你必须将大小作为参数(模板或普通)传递给函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-07
  • 2010-09-16
  • 2013-10-28
  • 1970-01-01
  • 1970-01-01
  • 2013-05-08
相关资源
最近更新 更多