请考虑以下代码,该代码包含在我的库中。
#include <complex>
std::complex<double> besselJ(int order, std::complex<double> z)
{
// Function call
}
std::complex<double> besselH1(int order, std::complex<double> z)
{
// Function call
}
请注意,这两个函数具有相同的签名。现在,我想编写第三个函数,无论它是作用于besselJ
还是besselH1
,它都完全相同。我尝试了以下
template<std::complex<double> (*T)(int, std::complex<double>)>
std::complex<double> diffBessel(int order, std::complex<double> z)
{
return T(order-1, z)-T(order+1,z);
}
当成员函数尝试使用语法diffbessel<besselJ>(int, std::complex<double>
时,GCC会抱怨the value of 'besselJ' is not usable in a constant expression
。有关说明,请参阅this answer。
有没有办法像上面的模板化代码一样,如果它工作而不需要在besselJ
中包装besselH1
和struct
?我认为结构会增加不必要的复杂性。
更新:这非常有效,正如@aschepler建议的那样。实际代码中存在名称冲突。看到它需要额外的第1001个外观。我被其他StackOverflow文章搞糊涂了,因为函数指针是可变的,所以这不会起作用。
答案 0 :(得分:4)
<强>的前提:强>
如果您的示例中的besselJ
是函数的名称,而不是您用作模板参数的变量的名称,则传递一个函数指针作为非类型模板参数应该工作。
查看live example。
替代解决方案:
如果函数指针保存在其运行时计算值的变量中,则不允许将该函数指针用作模板参数。如果要使用运行时函数指针,可以使用常规函数参数而不是模板参数:
#include <complex>
std::complex<double> diffBessel(
std::complex<double> (*fxn)(int, std::complex<double>),
int order,
std::complex<double> z
)
{
return fxn(order-1, z) - fxn(order+1,z);
}
更多IDIOMATIC SOLUTION:(需要C ++ 11)
如果您想要更灵活,使用C ++ 11可以使用std::function<>
:
#include <complex>
#include <functional>
std::complex<double> diffBessel(
std::function<std::complex<double>(int, std::complex<double>)> fxn,
int order,
std::complex<double> z
)
{
return fxn(order-1, z)- fxn(order+1,z);
}
在这两种情况下,您的函数都可以这样调用:
int main()
{
std::complex<double> c;
/* ... */
diffBessel(besselH1, 2, c);
}
进一步的可能性:
另一种可能性是,如果您不想或不能使用std::function<>
,您可以让您的函数接受任何可调用对象,方法是将其作为模板:
template<typename F>
std::complex<double> diffBessel(
F f,
int order,
std::complex<double> z
)
{
return f(order-1, z) - f(order+1,z);
}
同样,您可以使用与调用先前版本完全相同的方式调用此方法。
答案 1 :(得分:3)
模板需要在编译时知道它们的参数。在运行时从模板中拉出模板参数将不起作用。
只需将函数指针作为函数参数即可。它不需要是模板函数。
std::complex<double> diffBessel(int order,
std::complex<double> z,
std::complex<double> (*T)(int, std::complex<double>))