如何在C ++中编写使用其他函数的函数

时间:2013-03-07 21:41:14

标签: c++ templates function-pointers

请考虑以下代码,该代码包含在我的库中。

#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中包装besselH1struct?我认为结构会增加不必要的复杂性。

更新:这非常有效,正如@aschepler建议的那样。实际代码中存在名称冲突。看到它需要额外的第1001个外观。我被其他StackOverflow文章搞糊涂了,因为函数指针是可变的,所以这不会起作用。

2 个答案:

答案 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>))