C ++ Variadic模板基础知识

时间:2015-12-01 16:06:19

标签: c++ templates function-pointers

我正在尝试编写一个数值方法,它可以接受一个函数作为一个本身具有任意参数的参数。这样做的最佳方法似乎是使用可变参数模板。这个https://stackoverflow.com/a/15960517/3787488答案几乎就是我所需要的,但我的代码不会编译。

这是我的测试用例;

#include<iostream>
#include<vector>
#include<fstream>
#include<functional>
#include<iomanip>


double testfunction(double x, double k);

template<typename... Ts>
using custom_function_t = double(*) (double, Ts...);

template< typename... Ts>
double test( custom_function_t<Ts...> f, Ts... args, double min, double max, int m, int n)
{
    double ans=0;
    double step=(max-min)/100.00;
    for (double x=min;x<=max;x=x+(max-min)/100)
    {
        ans=ans+(step/6.0)*(f(x, args...)+4*f(x+0.5*step, args...)+f(x+step, args...));
    }
    return(ans);
}

int main()
{
    double ans=0;
    std::cout<<test(testfunction,2.0,0.0,1.0,0,0)<<endl;
    return(0);
}

double testfunction(double x, double k)
{
    double ans=0;
    ans=x*x*k;
    return(ans);
}

函数'test'应该使用函数'testfunction'并对其进行数值积分(2 * x ^ 2从0到1 = 2/3的积分)。

使用gcc编译4.7.3 c ++ 11我得到了错误;

note: template<class ... TS> double test (custom_function_t<Ts ...>, Ts ..., double, double, int, int)
note: template argument deduction/substitution failed:
note: candidate expects 5 arguments, 6 provided

2 个答案:

答案 0 :(得分:1)

在C ++中(自2011年起),这样的事情最好使用lambda,通过模板参数捕获,该模板参数可以是任何可调用对象:

#include<iostream>
#include<iomanip>
#include<cassert>

template<typename Func>   // anything that allows operator()(double)
double test(Func const&func, double x, const double max,
            const unsigned num_intervals=100)
{
  assert(num_intervals>0);
  const double dx=(max-x)/num_intervals;
  const double dx_half=0.5*dx;
  const double dx_third=dx/3.0;
  const double dx_two_third=dx_third+dx_third;
  double sum = 0.5*dx_third*func(x);
  for(unsigned i=1; i!=num_intervals; ++i) {
    sum += dx_two_third * func(x+=dx_half);
    sum += dx_third     * func(x+=dx_half);
  }
  sum+=dx_two_third* func(x+=dx_half);
  sum+=0.5*dx_third* func(x+=dx_half);
  return sum;
}

double testfunction(double, double);

int main()
{
  std::cout<<std::setprecision(16)
           <<test([](double x) { return testfunction(x,2.0); }, 0.0,1.0)
           <<std::endl;
}

double testfunction(double x, double k)
{
  return x*x*k;
}

另请注意,我避免为同一个值多次评估函数。

答案 1 :(得分:0)

编译器无法从提供的参数中推断出参数包的大小,除非包在最后。

正如您所发现的那样,如果您重新排序参数,它就会起作用。

另一个选择是通过明确地给出参数来保存它不必推断它们:

test<double>(testfunction, 2.0, 0.0, 1.0, 0, 0)

我不确定GCC为什么不能从您传递的函数指针中推断出参数,但是EDG编译器也不能这样做,给出了这个错误:

"var.cc", line 20: error: no instance of function template "test" matches the
          argument list
            argument types are: (double (*)(double, double), double, double,
                      double, int, int)
      test(testfunction, 2.0, 0.0, 1.0, 0, 0);
      ^

我的Clang 3.8.0版本在原始代码上崩溃,3.5.0拒绝它。如果我删除了别名模板并将test声明为

template< typename... Ts>
double test( double(*f)(double, Ts...), Ts... args, double min, double max, int m, int n)

然后Clang 3.50和3.80都快乐地编译它。