【发布时间】:2015-06-11 12:15:20
【问题描述】:
我可以使函数模板由其他函数参数化,但是,当我想通过具有不同数量参数的函数对其进行参数化时,我不知道该怎么做。
查看此代码:
#include <stdio.h>
#include <math.h>
template < double FUNC( double a ) >
void seq_op( int n, double * as ){
for (int i=0; i<n; i++){ printf( " %f \n", FUNC( as[i] ) ); }
}
template < double FUNC( double a, double b ) >
void seq_op_2( int n, double * as, double * bs ){
for (int i=0; i<n; i++){ printf( " %f \n", FUNC( as[i], bs[i] ) ); }
}
double a_plus_1 ( double a ){ return a + 1.0; }
double a_sq ( double a ){ return a*a; }
double a_plus_b ( double a, double b ){ return a + b; }
double a_times_b( double a, double b ){ return a * b; }
double as[5] = {1,2,3,4};
double bs[5] = {2,2,2,2};
// FUNCTION ====== main
int main(){
printf( "seq_op <a_plus_1> ( 5, as );\n"); seq_op <a_plus_1> ( 4, as );
printf( "seq_op <a_sq> ( 5, as );\n"); seq_op <a_sq> ( 4, as );
printf( "seq_op_2 <a_plus_b> ( 5, as, bs );\n"); seq_op_2 <a_plus_b> ( 4, as, bs );
printf( "seq_op_2 <a_times_b> ( 5, as, bs );\n"); seq_op_2 <a_times_b> ( 4, as, bs );
}
有没有办法为这两种情况制作通用模板?
为什么我需要这么傻的东西?一个更实际的例子是这两个函数,它们只有一行不同:
#define i3D( ix, iy, iz ) ( iz*nxy + iy*nx + ix )
void getLenardJonesFF( int natom, double * Rs_, double * C6, double * C12 ){
Vec3d * Rs = (Vec3d*) Rs_;
int nx = FF::n.x;
int ny = FF::n.y;
int nz = FF::n.z;
int nxy = ny * nx;
Vec3d rProbe; rProbe.set( 0.0, 0.0, 0.0 ); // we may shift here
for ( int ia=0; ia<nx; ia++ ){
printf( " ia %i \n", ia );
rProbe.add( FF::dCell.a );
for ( int ib=0; ib<ny; ib++ ){
rProbe.add( FF::dCell.b );
for ( int ic=0; ic<nz; ic++ ){
rProbe.add( FF::dCell.c );
Vec3d f; f.set(0.0,0.0,0.0);
for(int iatom=0; iatom<natom; iatom++){
// only this line differs
f.add( forceLJ( Rs[iatom] - rProbe, C6[iatom], C12[iatom] ) );
}
FF::grid[ i3D( ia, ib, ic ) ].add( f );
}
rProbe.add_mul( FF::dCell.c, -nz );
}
rProbe.add_mul( FF::dCell.b, -ny );
}
}
void getCoulombFF( int natom, double * Rs_, double * kQQs ){
Vec3d * Rs = (Vec3d*) Rs_;
int nx = FF::n.x;
int ny = FF::n.y;
int nz = FF::n.z;
int nxy = ny * nx;
Vec3d rProbe; rProbe.set( 0.0, 0.0, 0.0 ); // we may shift here
for ( int ia=0; ia<nx; ia++ ){
printf( " ia %i \n", ia );
rProbe.add( FF::dCell.a );
for ( int ib=0; ib<ny; ib++ ){
rProbe.add( FF::dCell.b );
for ( int ic=0; ic<nz; ic++ ){
rProbe.add( FF::dCell.c );
Vec3d f; f.set(0.0,0.0,0.0);
for(int iatom=0; iatom<natom; iatom++){
// only this line differs
f.add( forceCoulomb( Rs[iatom] - rProbe, kQQs[iatom] );
}
FF::grid[ i3D( ia, ib, ic ) ].add( f );
}
rProbe.add_mul( FF::dCell.c, -nz );
}
rProbe.add_mul( FF::dCell.b, -ny );
}
}
【问题讨论】:
-
我认为你能得到的最多就是重载,所以只需将两个函数命名为 seq_op,但仍然具有不同的实现
-
我尝试将它们的实现放在一起,而不是拥有两个(或更多)差异很小的复杂函数。可以使用默认参数(恕我直言,在您的情况下是最佳选择)、
bool或enum标志、函数指针等来实现。 -
是我,还是 c++11 中添加的 lambdas 来解决这类问题?
-
Melebius > 出于性能原因,我不想将任何不必要的
switch或if放在最里面的循环中。即使是函数指针,我也发现它不如模板或宏在编译时得到优化。可能可以通过宏来解决,但我发现模板更漂亮的编码风格和更具可读性。
标签: c++ templates metaprogramming