1

考虑以下代码,它包含在我制作的库中。

#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。请参阅此答案以获取解释。

有没有办法像上面的模板化代码一样,如果它在不使用包装besselJbesselH1in structs 的情况下工作的话?我认为结构会增加不必要的复杂性。

更新:这很好用,正如@aschepler 建议的那样。实际代码中存在名称冲突。花了额外的第 1001 次看才能看到它。我对其他 StackOverflow 文章感到困惑,这些文章暗示这不起作用,因为函数指针是可变的。

4

2 回答 2

4

前提:

假设besselJ在您的示例中是函数的名称,而不是您用作模板参数的变量的名称,那么将函数指针作为非类型模板参数传递应该可以工作。

看一个活生生的例子

替代解决方案:

如果您的函数指针保存在其值在运行时计算的变量中,则不允许您将该函数指针用作模板参数。如果要使用运行时函数指针,可以只使用常规函数参数而不是模板参数:

#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);
}

更惯用的解决方案:(需要 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);
}

同样,您调用它的方式与调用先前版本的方式完全相同。

于 2013-03-07T21:44:38.243 回答
3

模板需要在编译时知道它们的参数。在运行时将模板参数从变量中拉出是行不通的。

只需将函数指针作为函数参数即可。它不需要是模板函数。

std::complex<double> diffBessel(int order,
                                std::complex<double> z,
                                std::complex<double> (*T)(int, std::complex<double>))
于 2013-03-07T21:44:23.600 回答