关于使用类成员函数作为模板参数的问题

时间:2011-07-26 17:32:05

标签: templates

我正在阅读Daoqi Yang的书“C ++和面向对象的科学家和工程师的数字计算”。他有一个类似于我在下面显示的例子,但例外是我定义的类“P”和倒数第二行(它不起作用)。我的问题是:当我提供函数成员f.integrand时,为什么我的编译器生成并出错?我该怎么做才能纠正这个问题?生成的错误是C3867,C2440和C2973。

以下是代码:

class P{
public:
double integrand(double x){
    return (exp(-x*x));
}
};

template<double F(double)>
double trapezoidal(double a, double b, int n)
{
    double h=(b-a)/n;
    double sum=F(a)*0.5;
    for(int i=1;i<n;i++)
    {
        sum+=F(a+i*h);
    }
    sum+=F(b)*0.5;

    return (sum*h);
}

double integrand2(double x){
    return (exp(-x*x));
}

int main(){
    P f;
    cout<< trapezoidal<integrand2>(0,1,100)<<endl;    // this works
    cout<< trapezoidal<f.integrand>(0,1,100)<<endl;   // this doesn't work
}

2 个答案:

答案 0 :(得分:1)

模板参数必须是编译时常量表达式或类型,而成员函数无论如何都需要特殊处理。不要这样做,而是使用boost::function<>作为参数,并boost::bind来创建仿函数,例如。

double trapezoidal(double, double, boost::function<double(double)>);

// ...

P f;
trapezoidal(0, 1, 100, integrand2);
trapezoidal(0, 1, 100, boost::bind(&P::integrand, boost::ref(f)));

如果你有支持0x的编译器,你可以改用std::functionstd::bind

答案 1 :(得分:1)

Cat Plus Plus是正确的 - boost::bind是一种很容易做到这一点的好方法。我还提供了一个备用解决方案,其中包含以下代码片段:

class P{
private:
    double a;
public:
    double integrand(double x){
        return (a*exp(-x*x));
    }
    void setA(double y){
        a = y;
    }
    void getA(){
        cout<<a<<endl;
    }

    struct integrand_caller {
        P* p;
        integrand_caller(P& aP) : p(&aP) {};
        double operator()(double x) const {
            return p->integrand(x);
        };
    };
};

template <typename Evaluator, typename VectorType>
VectorType trapezoidal(Evaluator f, const VectorType& a, const VectorType& b, int n)
{
    VectorType h=(b-a)/n;
    VectorType sum=f(a)*0.5;
    for(int i=1;i<n;i++)
    {
        sum+=f(a+i*h);
    }
    sum += f(b)*0.5;

    return (sum*h);
}

double integrand2(double x){
    return (exp(-x*x));
}

int main(){
    P f[5];
    for(int i=0;i<5;i++){
        f[i].setA(5*i);
        f[i].getA();
        cout<< trapezoidal(P::integrand_caller(f[i]),(double)0, (double)1, 100) << endl;
        cout<<trapezoidal(boost::bind(&P::integrand,f[i],_1), 0.0, 1.0, 100)<<"\n"<<endl;
    }
}