如何将双参数函数"cast"为单参数函数?

How to "cast" a two-argument function into a one-argument function?

本文关键字:函数 参数 单参数 cast      更新时间:2023-10-16

在matlab中可以这样写:

S = @(x,y) x^2+y^2-1
G = @(x) S(x,1);

如果我有一个期望一个单参数函数的函数,我可以这样做。我如何在c/c++中做到这一点?

我有一个库函数(来自CGAL库),它期望作为参数的函数本身只有一个参数。理想情况下,我有一个类(SphericalHarmonics),我想有一个成员函数,它接受一个参数。输入:

FT SphericalHarmonics::distFunction(Point_3 p)

(注意,FT是一个类型类似于double),但当然,当我尝试

SphericalHarmonics *sh = new SphericalHarmonics(1);
Surface_3 surface(sh->distFunction, Sphere(ORIGIN,2.));

this也被视为参数,我的distFunction函数是一个双参数函数,并抛出错误。

请注意,这可以通过全局变量来解决,即

SphericalHarmonics *sh;
FT dist_function(Point_3 p) {
    return sh->distFunction(p);
}
main() {
    sh = new SphericalHarmonics(1);
    Surface_3 surface(dist_function);
}

然而,这确实是不理想的。我想要一种没有全局变量的方法来做到这一点,因为能够有一个容易与CGAL库集成的类函数要好得多。

提前感谢!

(更新)

@Andy-Prowl:我已经尝试了你的std::bindlambda解决方案,但似乎仍然遇到了关于参数数量的错误。

当,在main中,我使用代码:

SphericalHarmonics *sh = new SphericalHarmonics(cInit, numL, symm);
auto fxn = std::bind(&SphericalHarmonics::distFunction, sh, std::placeholders::_1);
Surface_3 surface(fxn, Sphere_3(ORIGIN,2.));

我得到错误:

~/lib/basisfunctions/SphericalHarmonics2/mesh_an_implicit_function.cpp:62:48: 
error: no matching function for call to     
‘CGAL::Implicit_surface_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, 
double (*)
(CGAL::Point_3<CGAL::Epick>)>::Implicit_surface_3(std::_Bind<std::_Mem_fn
<double (SphericalHarmonics::*)(CGAL::Point_3<CGAL::Epick>)>
(SphericalHarmonics*, std::_Placeholder<1>)>&, Sphere_3)’

~/CGAL-4.1/include/CGAL/Implicit_surface_3.h:50:5: note:   no known conversion 
for argument 1 from ‘std::_Bind<std::_Mem_fn<double (SphericalHarmonics::*)
(CGAL::Point_3<CGAL::Epick>)>(SphericalHarmonics*, std::_Placeholder<1>)>’ to 
‘CGAL::Implicit_surface_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, 
double (*)(CGAL::Point_3<CGAL::Epick>)>::Function 
{aka double (*)(CGAL::Point_3<CGAL::Epick>)}’

~/CGAL-4.1/include/CGAL/Implicit_surface_3.h:34:9: note:   
candidate expects 1 argument, 2 provided
(更新)

现在对我来说很清楚,我需要一个可以转换为函数指针的函数(即surface需要函数指针参数)。这就排除了std::bind选项。此外,如果lambda捕获变量(无捕获vs.捕获lambda),则它似乎不能转换为函数指针。所以我认为Andy-Prowl下面的答案通常是这个问题的正确答案,尽管我需要找到一个不同的解决方案。

选项1:

如果您的成员函数不隐式地工作在类的实例上(因此不需要接收this指针),您可以将其设置为static:

class SphericalHarmonics
{
    ...
    static double distFunction(Point p);
    ...
};
double SphericalHarmonics::distFunction(Point p)
{
    ...
}
现在,您的函数将有效地拥有一个参数:
surface(SphericalHarmonics::distFunction);

选项2:

否则,您可以使用std::bind()来curry成员函数distFunction并修复其第一个隐式参数(如果您不使用c++ 11编译器,您可以使用Boost中的等效boost::bind())。绑定库):

#include <functional>
SphericalHarmonics *sh = new SphericalHarmonics(1);
auto fxn = std::bind(&SphericalHarmonics::distFunction, sh, _1);
surface(fxn);

选项3:

或者,在c++ 11中,lambda可以完成这项工作:

SphericalHarmonics *sh = new SphericalHarmonics(1);
auto fxn = [=] (double d) { return sh->distFunction(d); } 

使用std::bind或boost::bind:

#include <functional>   
SphericalHarmonics *sh = new SphericalHarmonics(1);
surface(std::bind(&SphericalHarmonics::distFunction, sh, _1));

在处理CGAL模板化的Surface_3类的具体情况下。您可能会使用类似这样的内容(来自他们的示例)来定义Surface_3类型:

typedef CGAL::Surface_mesh_default_triangulation_3 Tr;
// c2t3
typedef CGAL::Complex_2_in_triangulation_3<Tr> C2t3;
typedef Tr::Geom_traits GT;
typedef GT::Sphere_3 Sphere_3;
typedef GT::Point_3 Point_3;
typedef GT::FT FT;
typedef FT (*Function)(Point_3);
typedef CGAL::Implicit_surface_3<GT, Function> Surface_3;

这是误导,因为它使它看起来像CGAL的等值面类只能处理函数指针(与std::function等相反)。但问题只是我们用的方式定义了它。只要定义Surface_3使用std::function<FT (Point_3)>作为模板参数,Andy Prowl的答案中的std::bind和lambdas就可以正常工作:

...
typedef std::function<FT (Point_3)> Function;
typedef CGAL::Implicit_surface_3<GT, Function> Surface_3;