C++ 可变参数模板基础
C++ Variadic Template Basics
我正在尝试编写一个数字方法,该方法可以接受一个函数作为参数,而该函数本身具有任意参数。最好的方法似乎是使用可变参数模板。 答案几乎正是我所需要的,但我的代码无法编译。
这是我的测试用例;
#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
除非参数包位于末尾,否则编译器无法从提供的参数中推断出参数包的大小。
正如您所发现的,如果您重新排列参数,它会起作用。
另一种选择是通过显式给出参数来避免必须推断它们:
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都能顺利编译
在 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;
}
另请注意,我避免为同一值多次计算函数。
我正在尝试编写一个数字方法,该方法可以接受一个函数作为参数,而该函数本身具有任意参数。最好的方法似乎是使用可变参数模板。 答案几乎正是我所需要的,但我的代码无法编译。
这是我的测试用例;
#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
除非参数包位于末尾,否则编译器无法从提供的参数中推断出参数包的大小。
正如您所发现的,如果您重新排列参数,它会起作用。
另一种选择是通过显式给出参数来避免必须推断它们:
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都能顺利编译
在 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;
}
另请注意,我避免为同一值多次计算函数。