2013-03-07 129 views
1

请考虑下面的代码,它包含在我制作的库中。如何编写在C++中使用其他函数的函数

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

注意两个函数都有相同的签名。现在,我想编写第三个函数,它执行的操作与besselJbesselH1完全相同。我尝试以下

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

有没有办法做一些像上面的模板代码,如果它的工作而不是诉诸于struct小号包装besselJbesselH1会做什么?我认为结构会增加不必要的复杂性。

更新:这个工程很漂亮,就像@aschepler建议它应该那样。实际代码中存在名称冲突。这花了额外的第1001次看看。我被其他StackOverflow文章弄糊涂了,这些文章暗示这不起作用,因为函数指针是可变的。

+1

链接的答案并不能解释为什么'diffbessel (args)'不起作用。据我所知,它应该工作。 – aschepler 2013-03-07 21:47:00

+0

你能显示GCC抱怨的确切代码吗? – Angew 2013-03-07 21:56:43

+0

感谢你们俩。它**可以**工作。尽管我看了几个小时的代码,但我忽略了一个愚蠢的错误。 – 2013-03-07 22:12:46

回答

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

更地道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); 
} 

同样,您将调用此方法与调用以前版本的方式完全相同。

+0

我想过使用'std :: function',但在[文章](http://stackoverflow.com/questions/9054774/difference-between-stdfunction-and-a-standard-function-pointer)比较'std :: function'和函数指针,除非需要额外的功耗,否则不鼓励使用'std :: function'。 – 2013-03-07 22:16:52

+0

@JoeyDumont:决定是否使用'std :: function'主要是基于你的用例。 'std :: function'允许更多的灵活性(你可以传入一个lambda,一个函数,任何东西),它的“坏”性能(在大多数情况下是虚函数调用)只有在你证明它时才会成为问题成为瓶颈。否则,你应该关注干净的设计。这就是说,你不需要*使用'std :: function'。你可以使用常规函数指针,但是作为函数参数,而不是模板参数。 – 2013-03-07 22:20:04

+0

@JoeyDumont:无论如何,正如我在答案的开头写的那样,只要你没有传入*变量*的值,模板参数也应该适用于你的情况。如果你是,也就是说,如果要在运行时确定要使用的函数,那么你几乎不得不使用函数参数而不是模板参数:是选择常规指针还是选择std :: function '取决于你。就我个人而言,我会去第二个。 – 2013-03-07 22:21:43

3

模板需要在编译时知道它们的参数。在运行时将模板参数拉出变量不起作用。

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

std::complex<double> diffBessel(int order, 
           std::complex<double> z, 
           std::complex<double> (*T)(int, std::complex<double>)) 
+0

确实,但这失败了,因为我有另一个函数,使用基地函数'diffBessel'。我需要一个可变数量的函数指针,而这绝对不是最好的。不过谢谢你的想法。 – 2013-03-07 22:11:28

相关问题