如何将双参数函数转换为单参数函数?

问题描述:

在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库的类函数会更好。

在此先感谢!

[增订]

@安迪警车:我想你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选项。此外,如果它捕获变量(capture-less vs. capturing lambdas),看起来lambda不能被转换为函数指针。所以我认为Andy-Prowl的回答总的来说是这个问题的正确答案,但我需要找到一个不同的解决方法。

+3

(我还没有真正阅读问题)绑定或拉姆达? – 2013-02-28 00:15:33

+0

这些标签有误导性,应该包含matlab/lambda – Dmitry 2013-02-28 00:25:03

+0

这些解决方案中的任何一个都可以正常工作吗?是不是可以使用bind来代替函数指针? – 2014-09-04 21:36:07

选项1:

如果你的成员函数并不暗示对你的类的实例工作(并因此不需要接收this指针),你可以使它static

class SphericalHarmonics 
{ 
    ... 
    static double distFunction(Point p); 
    ... 
}; 

double SphericalHarmonics::distFunction(Point p) 
{ 
    ... 
} 

现在,您的功能将有效地具有一个参数:

surface(SphericalHarmonics::distFunction); 

选项2:

否则,您可以使用​​讨好成员函数distFunction和修复其第一,隐含参数(如果您不与C++编译器11的工作,你可以从Boost.Bind库使用等效boost::bind()):

#include <functional> 

SphericalHarmonics *sh = new SphericalHarmonics(1); 
auto fxn = std::bind(&SphericalHarmonics::distFunction, sh, _1); 
surface(fxn); 

OPTION 3:

另外,在C++ 11,一个lambda可以做的工作:

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

谢谢!我确信这是正确的,所以我已经检查过了。选项1不是一个选项(我想处理特定的类实例)。当我尝试选择2或3时,我得到错误'错误:'fxn'没有命名一个类型'和'错误:'fxn'没有在这个范围内声明。我试过'std :: bind'和'boost :: bind'(包括''和''),我得到了同样的错误。在Ubuntu 12.04上使用gcc 4.6.3版本 – OwenM 2013-02-28 01:10:33

+0

@OwenM:你是否在使用带有-std = C++ 0x或者-std = C++ 11命令行选项的C++ 11编译器? 'auto'关键字需要C++ 11。我也建议你升级到GCC 4.7.2,你使用的版本是相当老的。还有[这个网站](http://www.liveworkspace.org),你可以用不同的编译器编译你的代码。 – 2013-02-28 01:17:20

+0

是的,gcc 4.7.2与-std = C++ 11修复了这个问题! – OwenM 2013-02-28 17:00:51

使用std::bindboost::bind

#include <functional> 

SphericalHarmonics *sh = new SphericalHarmonics(1); 
surface(std::bind(&SphericalHarmonics::distFunction, sh, _1)); 
+1

你的意思是sh而不是这个? – Slava 2013-02-28 00:20:23

+0

@Slava是的,谢谢。 – Drax 2013-02-28 00:21:17

在处理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's answerstd::bind和lambda表达式会工作得很好:

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